I want to do something like class categories in Objective-C, to define a class in one file, implement some core methods there, then implement some helper methods in another without subclassing or interfaces, just "continue" the class.
Possible in PHP?
As of PHP 5.4, you can accomplish this with Traits. To quote the official documentation:
Traits [enable] a developer to reuse sets of methods freely in several independent classes living in different class hierarchies. [...] A Trait is similar to a class, but only intended to group functionality in a fine-grained and consistent way. It is not possible to instantiate a Trait on its own. It is an addition to traditional inheritance and enables horizontal composition of behavior; that is, the application of class members without requiring inheritance.
Using a trait allows you to store helper methods that address cross-cutting concerns in a central place and use these methods in whatever classes you need.
// File "HelperMethodTrait.php"
trait HelperMethodTrait
{
public function myIncredibleUsefulHelperFunction()
{
return 42;
}
}
// File "MyClass.php"
class MyClass
{
use HelperMethodTrait;
public function myDomainSpecificFunction()
{
return "foobar";
}
}
$instance = new MyClass();
$instance->myIncredibleUsefulHelperFunction(); // 42
a-priori PHP doest not give you this feature by language construction, the whole class must be in a single file.
Now there are tricks that could do the stuff, but they are quite heavy CPU demanding:
You can for example dissociate your classes between different files, then load the files and build a single string with the whole code, then do an eval(string) to interprete the classes and build them into the runnable code area.
not really a good idea btw for many reasons
If your only goal is to make the class definition file smaller, you can include files within a function definition
class MyClass {
public function doStuff($foo,$bar) {
global $quz;
include('MyClass.doStuff.php');
}
}
Within the include, your local scope applies ($foo,$bar and $quz will be defined)
I'm not sure what the overhead is - the include seems to happen at run-time, not compile time (since an include can actually return a value ..)
I think you better split your class in n parts along functional criteria, and then use the dependency injection pattern to "inject" class A into class B in the constructor for B, without a need for subclassing/interfaces.
You could use this method to add functions to some objects externally, which is different from adding methods to the class itself.
https://stackoverflow.com/a/2938020/2277620
Another not-so-good-way is it create a multiple subclasses so every level of subclasses add only a 'group' of functions.
I used this trick in a single case where a class was more than 10k rows.
Now I've 6 levels of inheritance where every level add a single 'category' of functions the the "previous level" class.
Not so cpu-consuming, ugly to see, not so difficult to maintain
It is highly dependant on what you wish to achieve. I had this bright idea doing what you wish to do. I likes the key words set, get run delete etc. Suppose there was a class and I wanted set of delete. As Ph.T pointed out class needs to be in single file
So make abc->set in one file and abc->get in another file made no use and sense.
So had to lot of rethinking and think of classes as micro services doing specific tasks broken down in functionality.
Solution went with name spacing.
namespace A;
class Get{public static function myCode(){}
public static function myAnotherCode(){}}
this would then be called A\Get::myCode(); or A\Get::myAnotherCode();
Similarly set would be
namespace A;
class Set{public static function myCode(){}
public static function myAnotherCode(){}}
This would then be called A\Set::myCode(); or A\Set::myAnotherCode();
Then user spl_autoload_register to load classes remember to replace \ with /
spl_autoload_register(function ($class) {
require_once __DIR__ . '/' . strtolower(str_replace('\\', '/', $class) . '.php')
});
and directory structure is as following
main (folder)
-- A (folder)
-- set.php (file)
-- get.php (file)
we asked for A\Get::myCode()
require would see it as A/Get.php then run its logic whether it is right name space or class etc.
good side of it if planned out right is it would force you to run things run in logical not just wishy washy there and there. Second you would only load functionality what you need not just whole bunch of this and that.
down side two parts of classes wont share between them unless one extends one from another which would defy the whole logic because other one would be loaded as a consequence any ways.
Careful negation has to be made as in what logic and planning data will be shared and has to be worked out before hand.
namespace A;
class Universal {
protected static $share_one;
protected static $share_two;
}
namespace A;
class Set extends Universal {
public static function myCode(){ parent::$share_one ='wow';}
}
namespace A;
class Get extends Universal {
public static function myCode(){ return parent::$share_one;}
}
main (folder)
-- A (folder)
-- universal.php (file)
-- set.php (file)
-- get.php (file)
run the code and see the magic
A\Set::myCode();
echo A\Get::myCode();
if you only need one set of functionality e.g. get then just use get echo A\Get::myCode(); would work without errors.
To be honest without playing around with name spaces its just expenditure of time earning headaches.
Side note: if done right it can speed up things as class universal wont load twice. even if called gazillion times whats what we want load defaults and then populate them where ever we need them. I have made huge classes where besides defaults only needed few functions rest was just memory load. breaking down just spead up things.
Related
How can I add a static method for all classes of my php using an class Class or class Object (meta class) like
class Object //meta class, all classes php henerit of it
{
static function test() { return 42; }
}
now if I make a new class like :
class User
{
}
I want to be abble to write :
User::test();
same with all classes I will write
PHP has no concept of metaclasses; the way in which classes themselves behave is essentially hard-coded into the language. (You could argue that internal classes written in C conceptually use a different metaclass than userland classes written in PHP, since they can implement a different set of hooks; but that's not a distinction that's visible in the language, and not really relevant to your example.)
It also has no universal base class; there is no "Object" or "Any" or "Mu" class which all other classes implicitly or explicitly inherit from.
More importantly, there is no way to add to an existing class; there is no way to "re-open" or "monkey-patch" a class, or add methods via "extension classes". So even if there was a default metaclass or universal base class, you wouldn't be able to change it. Any classes you wanted extra behaviour on would have to opt-in to being instances of a non-default metaclass, or inherit from a non-default base class.
It's not clear exactly what the use case is, but there are a number of things you can do:
Write your own base class which a large number of classes inherit from, to put your "universal" methods in.
Use traits which enable "horizontal code re-use", essentially by "compiler-assisted copy-and-paste".
You have to use the trait in each class where you want to "paste" its contents, but they will then be inherited from there, so you can have a handful of unrelated "base classes" all sharing a set of methods "pasted" from the same trait.
On the other hand, you might want to create a sub-class which takes an existing class and adds some methods using a trait.
More complex cases would require you to patch the source code of classes themselves. For instance, using a custom autoloader and https://github.com/nikic/php-parser to parse and manipulate class definitions before they are compiled. For instance, this just-for-fun sweary library installs as a Composer plugin and loads classes via a stream wrapper which removes restrictions such as "final".
Why not use a trait?
Unfortunately I haven't heard of anything like what you need in PHP.
<?php
trait Obj
{
static function test() { return 42; }
}
class User
{
use Obj;
}
echo User::test(); //prints 42
Hope this helps.
As I looked for the new PHP7-features I stumbled upon anonymous classes.
I didn't understand when they should become useful, and looked for an example.
I read this article, but I don't see the benefits of this feature.
In the last section before the conclusion they wrote the following about the advantages:
One advantage is that we no longer need the named extension. Normally the named extension would be hidden away in some included file, if you ever needed to see how it is defined you have to start searching for it. With anonymous classes the definition is in the same place the object is created.
On the other hand, I see a big disadvantage because you can use this anonymous class only at the place it is defined.
Can someone please explain when this feature is useful?
Especially if it can help when building custom systems or extending a CMS like WordPress (preferably in German, although English is also welcome).
Anonymous classes could be useful in writing implementation classes for listener interfaces, so you don't need to create a file or a generic class just to implement once.
One of the most elegant things about anonymous classes is that they
allow you to define a one-shot class exactly where it is needed. In
addition, anonymous classes have a succinct syntax that reduces
clutter in your code. Java in a nutshell
So, you can have an anonymous implementation of an interface or even extend a class, with additional properties or overwritten methods.
Example:
return new class(10) extends SomeClass implements SomeInterface {
private $num;
public function __construct($num)
{
$this->num = $num;
}
};
Another situation:
Provide a simple implementation of an adapter class. An adapter class is one that defines code that is invoked by some other object. Take, for example, the list() method on a class called File. This method lists the files in a directory. Before it returns the list, though, it passes the name of each file to a FilenameFilter object you must supply. This FilenameFilter object accepts or rejects each file. When you implement the FilenameFilter interface, you are defining an adapter class for use with the $file->list() method. Since the body of such a class is typically quite short, it is easy to define an adapter class as an anonymous class.
$file = new File("/src");
// Now call the list() method with a single FilenameFilter argument
// Define and instantiate an anonymous implementation of FilenameFilter
// as part of the method invocation expression.
$filelist = $file->list(new class extends FilenameFilterClass {
public function accept(File $f, string $otherInfo) {
return pathinfo($f, PATHINFO_EXTENSION) === ".php";
}
});
Some nice basic understanding and use about anonymous classes could be found on Java (I know its not PHP, but it helps on understanding) examples at https://www.geeksforgeeks.org/anonymous-inner-class-java/
I should use a anonymous class only if this class is not used anywhere else and if these class isn't changed since the first coding.
So for example a database class could maybe a candidate for using a anonymous class because it should be use only once and could be included in any other php file. In most cases the data for accessing the database is in the config file. Therefore this file should be loaded for every php file that is using the database when you want to avoid the hard coding of the database params (which is a bad idea). If you coded these class as an anonymous class in the config file you have eliminated one include whithout losing the maintainance.
Ok, so I am building a web application relying on Zend PHP....
Before having to read everything to describe my nested functions, what I need is to be able to call a function from one class to another, which neither are extended upon another, are already extending a db constructor, which are all independently separate files called by one master initializing script .... (?) ... Thanks in advance, and there is a better example below as to what I mean.
My HTML Page calls a "master" include list which initializes and creates all the instances of all my classes so that all pages have common access to the functions. i.e. require('app_init.php');
Here is the most important excerpt of app_init.php:
require_once('class-general.php');
require_once('class-users.php');
require_once('class-identities.php');
$general = new General();
$users = new Users($db);
$iden = new Iden($db);
---class-general.php
$general is my basis for stupid common functions I use, as well as the DB constructor that all classes can be extended from.
----class-users.php
<?php
class Users extends General{
public function getUserID(){....random block of auth code.... return $randomID#; }
}?>
-----class-identities.php
<?php
class Iden extends General{
public function do_random_change_to_db($with_me){
....random prepared function using $with_me....
$this->logger->log("Someone with UserID: ". /*((?$this?) HERE:)*/ FIXME->getUserID() . " did something : ".$with_me ."." , Zend_Log::INFO);
$success="gucci";
return $success;
}
}?>
Right now, I am being tossed a PHP error for
Fatal error: Call to undefined method Iden::getUserID() in ...`
What would be the best way to go about this? I've tried to include one class file with the other one, but i dont exactly want to create a $FIXME= new Users(); either to save on memory space.
I also honestly would prefer to not extend any more classes off another at this time.
Thank you in advance.
If the getUserID method does not depend on any instance state (and it doesn't look like it does, though you haven't made it entirely clear), making it static will allow you to call it like so:
Users::getUserID();
If it does depend on instance state, you will need to call it on an instance of the Users class.
It seems to me that General's methods should actually be static as well, or perhaps even be free functions outside of a class. Remember: classes are used to encapsulate state. If there's no state that needs to be encapsulated, use class (static) methods or simple functions. Do not needlessly complicate your code by introducing objects and inheritance in which those paradigms don't make sense.
I was wondering if there is any major different in the following, and whether one is more 'standard' than the other:
<?php
class Account extends Database {
public function myMethod()
{
// Do something
}
}
?>
or
<?php
require('database.class.php');
class Account {
public function myMethod()
{
// Do something
}
}
?>
Cheers :)
Edit:
This question actually relates to a tutorial series I have been following which describes the above two methods - which didn't make any clear sense.
So thank you for the constructive answers on clearing that one up!
Those are two completely separate language constructs.
Your first example deals with inheritance. Basically, you already have a class called Database, but you want to have a specialized version of that class to handle accounts. Rather than build a brand new Account class and copy/paste all the functionality you already have in your Database class, you simply tell PHP that you want to use the existing Database class as a baseline. You create any account-specific functionality in the new Account class, and anything database-related comes automatically. This is assuming, of course, that you have some way of specifying where the Database class is defined - for example, a require declaration at the top of the class, or an __autoload() or spl_autoload_register() function call defining a way to find and locate the file containing the Database class.
In your second example, your database-related code is completely separated from your Account class. They're completely distinct entities, and if you wanted to do anything database-related in your Account class, you would have to explicitly instantiate a new Database object within that class (or pass it to that class, or one of its functions, as a parameter.
Basically, extends helps define what a class is, whereas require shows where a class definition (or other code) is stored.
Both code snippets aren't even equivalent.
The first declares Account to extend Database, a is-a relation.
In the second code snippet, you are simply saying that you require 'database.class.php' ... and that neither has anything to do with OO, nor defines a is-relation from Account to Database.
Both are completely different in first one class is inherited by another class but in the second one the class is included in your script only.
Means if you extend all the public and protected methods are available in your derived class and you can create object of derived class and can use methods with derived class's object.
But in the second method the class is included in your script and require this class it's own method and work independently.
The first means you create a new class, which has all the functionality of Database class and those you implement.
The second means that you create a new class, but it doesn't have Database functionality since it's not extending it. If you need database access in your Account class, you can create an instance in constructor, or pass already created instance as constructor parameter.
It's hard to say what is more standard, since it depends on what You actually want to achieve.
To put it in most simple terms:-
require or include is structural programming.
extends is object oriented
When extending classes in Java, class name ambiguity is avoided by the usage of qualified package names in the import statements.
For example: Say I want my controller to extend Spring's MultiActionController - I'll import the same from the standard Spring package. This also prevents me from extending Mike's or Perry's MultiActionController, since I have not imported MultiActionController from their packages.
Similarly in PHP, say we have 10 classes in 10 different library folders, all of which are called MultiActionController.
When I write:
class MyController extends MultiActionController {
function __construct() {
parent::__construct();
}
}
How do I tell PHP which MultiActionController (from which folder), to extend from?
Having several classes with the same name will, one day or another, cause some problems : you cannot include two classes with the same name during the execution of one script -- It'll get you a Fatal Error.
What's generally done, in PHP (before PHP 5.3 and namespaces, at least) is to include the name of the library and/or the "package" in the class name.
For instance, you could have a class name MyLibrary_Package_MultiActionController, and another called OtherLib_Blah_MultiActionController.
Then, what's generally done is using that class name to "map" it to directories and files, replacing the '_' by '/', and adding .php at the end of the last level -- this being often done using the autoloading feature of PHP, to avoid having to write an enormous amount of require directives.
For instance, a class named MyLibrary_Package_MultiActionController should be stored in MyLibrary/Package/MultiActionController.php.
As a sidenote : you used the tag "php4", in your question... If you are actually using PHP 4, you should not forget that it's old, not maintained anymore (Not even for security-related problems), and that PHP 5 is really the way to go !
In fact, you won't be able to do much about object-oriented programming, with PHP 4 ; the object-oriented stuff in PHP 4 was really basic...
(Stuff such as autoloading, which I wrote about a couple of paragraph earlier didn't exists in PHP 4 -- same for public/private/protected, and lots of other OO-related things...)
It depends which one you include. PHP will not let you redefine a class of the same name, so just include above the class definition (change to fit the file names and your software layout):
include('../includes/Spring/MultiActionController.php');
class MyController extends MultiActionController {
....
}
PHP will extend the class that you included with an include statement.
For example, say that you have a class foo declared in file bar.php:
class Foo {
// methods and fields
}
Then in another fie:
include 'bar.php';
class Aardvark extends Foo {
// this class will extend the class Foo in file bar.php
}
You have to include the file holding the class, with a banal include() statement:
include('lib/controllers/MultiAction.php');
Then you can extend it!
I would use namaspaces
namespace package_products_multicontroller {
include("/packages/products/multicontroller.php");
}
class MyController extends package_products_multicontroller\MultiActionController {
function __construct() {
parent::__construct();
}
}