Can I extend a class using more than 1 class in PHP?
Solution 1
If you really want to fake multiple inheritance in PHP 5.3, you can use the magic function __call().
This is ugly though it works from class A user's point of view :
class B {
public function method_from_b($s) {
echo $s;
}
}
class C {
public function method_from_c($s) {
echo $s;
}
}
class A extends B
{
private $c;
public function __construct()
{
$this->c = new C;
}
// fake "extends C" using magic function
public function __call($method, $args)
{
$this->c->$method($args[0]);
}
}
$a = new A;
$a->method_from_b("abc");
$a->method_from_c("def");
Prints "abcdef"
Solution 2
You cannot have a class that extends two base classes. You could not have the following:
// this is NOT allowed (for all you google speeders)
Matron extends Nurse, HumanEntity
You could however have a hierarchy as follows...
Matron extends Nurse
Consultant extends Doctor
Nurse extends HumanEntity
Doctor extends HumanEntity
HumanEntity extends DatabaseTable
DatabaseTable extends AbstractTable
and so on.
Solution 3
You could use traits, which, hopefully, will be available from PHP 5.4.
Traits is a mechanism for code reuse in single inheritance languages such as PHP. A Trait is intended to reduce some limitations of single inheritance by enabling a developer to reuse sets of methods freely in several independent classes living in different class hierarchies. The semantics of the combination of Traits and classes is defined in a way, which reduces complexity and avoids the typical problems associated with multiple inheritance and Mixins.
They are recognized for their potential in supporting better composition and reuse, hence their integration in newer versions of languages such as Perl 6, Squeak, Scala, Slate and Fortress. Traits have also been ported to Java and C#.
More information: https://wiki.php.net/rfc/traits
Solution 4
Classes are not meant to be just collections of methods. A class is supposed to represent an abstract concept, with both state (fields) and behaviour (methods) which changes the state. Using inheritance just to get some desired behaviour sounds like bad OO design, and exactly the reason why many languages disallow multiple inheritance: in order to prevent "spaghetti inheritance", i.e. extending 3 classes because each has a method you need, and ending up with a class that inherits 100 method and 20 fields, yet only ever uses 5 of them.
Solution 5
There are plans for adding mix-ins soon, I believe.
But until then, go with the accepted answer. You can abstract that out a bit to make an "extendable" class:
class Extendable{
private $extender=array();
public function addExtender(Extender $obj){
$this->extenders[] = $obj;
$obj->setExtendee($this);
}
public function __call($name, $params){
foreach($this->extenders as $extender){
//do reflection to see if extender has this method with this argument count
if (method_exists($extender, $name)){
return call_user_func_array(array($extender, $name), $params);
}
}
}
}
$foo = new Extendable();
$foo->addExtender(new OtherClass());
$foo->other_class_method();
Note that in this model "OtherClass" gets to 'know' about $foo. OtherClass needs to have a public function called "setExtendee" to set up this relationship. Then, if it's methods are invoked from $foo, it can access $foo internally. It will not, however, get access to any private/protected methods/variables like a real extended class would.
Related videos on Youtube
Comments
-
atomicharri over 2 years
If I have several classes with functions that I need but want to store separately for organisation, can I extend a class to have both?
i.e.
class a extends b extends c
edit: I know how to extend classes one at a time, but I'm looking for a method to instantly extend a class using multiple base classes - AFAIK you can't do this in PHP but there should be ways around it without resorting to
class c extends b
,class b extends a
-
Franck over 15 yearsUse aggregation or interfaces. Multiple inheritance doesn't exist in PHP.
-
atomicharri over 15 yearsI'm looking into interfaces as I'm not a big fan of large class hierarchies. But I can't see how interfaces actually do anything?
-
Franck over 15 yearsInterfaces enable you to "inherit" the API only, not function bodies. It forces class a to implement methods from interface b and c. It means that if you want to inherit behavior you must aggregate member objects of classes b and c in your class a.
-
Franck over 15 yearsI mean put private $b (instance of b) and private $c (instance of c) in your class a, if that wasn't clear enough.
-
Gordon about 14 yearsConsider using Decorators sourcemaking.com/design_patterns/decorator or Strategies sourcemaking.com/design_patterns/strategy
-
Halfstop about 8 yearsI'd question my design if I think that multiple inheritance the best solution to my problem. I ran down this road and came across this question. As a rule, if you're trying to do something that's not naturally supported by the language, you should question your design. Multiple inheritance seems unduly confusing and clunky.
-
Daniel almost 6 yearsPlease consider traits as the correct answer.
-
-
PhiLho over 15 yearsYet? I doubt they will do it. Modern OO discourage multiple inheritance, it can be messy.
-
atomicharri over 15 yearsI actually quite like the idea of extending the class Are there any known limitations of doing it this way?
-
Franck over 15 yearsNo limitations as far as I know, PHP is a very permissive language for little hacks like this. :) As others have pointed out, it's not the proper OOP way of doing it though.
-
Max Kielland over 13 yearsI love this idea, clean and simple!
-
wormhit over 11 yearsYou will not be able to use protected or private methods.
-
kaore almost 11 yearsThere is a comment which suggests a way to do this in the php doc, with the same limitation about protected and private methods php.net/manual/fr/keyword.extends.php#98665
-
MikeSchinkel over 10 yearsI'll take issue with your assertion that the OP's request constitutes "bad OO design"; just look at the emergence of Mixins to support the position that adding in methods to a class from multiple sources is a good idea architecturally. I will however give you that PHP does not provide an optimal set of language features to achieve an optimal "design" but that does not mean using the features available to approximate it is necessarily a bad idea; just look at @Franck's answer.
-
MikeSchinkel over 10 yearsThis effectively becomes the same thing that Franck and Sam show. Of course if you do choose to explicitly use composition you should be using dependency injection.
-
Denis V over 10 years@wormhit, though, I wouldn't recommend it for use in production, one can use ReflectionClass to access private and protected methods.
-
Qwerty about 10 yearsCan you explain why it is right to first inherit Nurse into Matron, then declare inheritance of HumanEntity into Nurse?
-
J-Dizzle over 9 years@Qwerty Because Matron has additional qualities of a Nurse, while a nurse has all the qualities of a human. Therefore, Matron is a human nurse and finally has Matron capabilities
-
AbcAeffchen over 9 yearsYour answer should contain an explanation of your code and a description how it solves the problem.
-
Erik about 9 yearsThis won't work for Implements, which expects the method to actually exist and the behaviour is pretty much undefined when multiple base classes have a method with the same name. It will also mess up your editor's ability to give you hints.
-
Heroselohim about 8 yearsIt's almost self explanatory, but it would be great to have comments along the code.
-
Nikola Petkanski over 7 yearsMake sure not to abuse them. Essentially they are static functions that you apply to objects. You could create a mess by abusing them.
-
Admin about 6 yearsI'm stuck with php 5.3 there's no trait support :D
-
Plixxer about 6 yearsI'm not quite sure why the community has upvoted this answer. initializing the object C is no where near the same as extending a class. With this method you drop support for property visibility and object inheritance. If i saw a coder write this in production based code, i would immediately fire them. The only case or scenario where code like this should be considered acceptable is if your writing a descriptive object, in which case it should probably be static unless your creating instances of the object in memory.
-
Plixxer about 6 years@wormhit in order to salvage protected or private visibility you will need to extend an extended class. In most cases this is not ideal.
-
Daniel almost 6 yearsI cannot believe this is not the selected answer.
-
SOFe over 5 years@rostamiani because this method is also modifying class
B
. What we want most of the time is to have two unrelated classesB
andC
(probably from different libraries) and get simultaneously inherited byA
, such thatA
contains everything from bothB
andC
, butB
doesn't contain anything fromC
and vice versa. -
SOFe over 5 yearsWhy not use the trait in
BusinessWoman
instead ofBusinessPerson
? Then you can have actual multi-inheritance. -
Alice over 5 years@SOFe, because BusinessMan can also extend it. So who ever is doing business can extend busines person, and gets traits automatically
-
SOFe over 5 yearsThe way you are doing this is no difference from what's possible in single inheritance where BusinessPerson extends an abstract class called human. My point is that your example doesn't really need multi inheritance.
-
Alice over 5 yearsI belive till BusinessPerson it was required, BusinessWoman could have directly inherited oth traits. But what I tried here is, keeping both traits in a mediator class and then use it, where ever required. So at I can forget about including both traits if again needed some where else (as per I described BusinessMan). It is all about code styles. If you like to include directly to your class. you can go ahead with that - as you are absolutely right about that.
-
SOFe over 5 yearsThe point is not whether it is required. The point is that your example, regardless of its business-logic-level meaning, does not demonstrate multi-inheritance at all.
-
Yevgeniy Afanasyev over 4 yearsinteresting and irrelevant.
-
Alice almost 4 yearsnow if Ext1 and Ext2 both have a function with same name always Ext1 cwill be called, it will not depend on parameters at all.
-
Alexander Behling almost 3 years@Daniel me too.
-
Peon over 2 yearsThis needs more votes, as in most cases, traits would be the implementation people need!
-
dewd over 2 yearsupdate for 2021: BusinessNonBinary extends BusinessPerson
-
MaXi32 over 2 yearsThis should be the selected answer as this is now considered as standard.