Multiple Inheritance in PHP

101,628

Solution 1

Alex, most of the times you need multiple inheritance is a signal your object structure is somewhat incorrect. In situation you outlined I see you have class responsibility simply too broad. If Message is part of application business model, it should not take care about rendering output. Instead, you could split responsibility and use MessageDispatcher that sends the Message passed using text or html backend. I don't know your code, but let me simulate it this way:

$m = new Message();
$m->type = 'text/html';
$m->from = 'John Doe <[email protected]>';
$m->to = 'Random Hacker <[email protected]>';
$m->subject = 'Invitation email';
$m->importBody('invitation.html');

$d = new MessageDispatcher();
$d->dispatch($m);

This way you can add some specialisation to Message class:

$htmlIM = new InvitationHTMLMessage(); // html type, subject and body configuration in constructor
$textIM = new InvitationTextMessage(); // text type, subject and body configuration in constructor

$d = new MessageDispatcher();
$d->dispatch($htmlIM);
$d->dispatch($textIM);

Note that MessageDispatcher would make a decision whether to send as HTML or plain text depending on type property in Message object passed.

// in MessageDispatcher class
public function dispatch(Message $m) {
    if ($m->type == 'text/plain') {
        $this->sendAsText($m);
    } elseif ($m->type == 'text/html') {
        $this->sendAsHTML($m);
    } else {
        throw new Exception("MIME type {$m->type} not supported");
    }
}

To sum it up, responsibility is split between two classes. Message configuration is done in InvitationHTMLMessage/InvitationTextMessage class, and sending algorithm is delegated to dispatcher. This is called Strategy Pattern, you can read more on it here.

Solution 2

Maybe you can replace an 'is-a' relation with a 'has-a' relation? An Invitation might have a Message, but it does not necessarily need to 'is-a' message. An Invitation f.e. might be confirmed, which does not go well together with the Message model.

Search for 'composition vs. inheritance' if you need to know more about that.

Solution 3

If I can quote Phil in this thread...

PHP, like Java, does not support multiple inheritance.

Coming in PHP 5.4 will be traits which attempt to provide a solution to this problem.

In the meantime, you would be best to re-think your class design. You can implement multiple interfaces if you're after an extended API to your classes.

And Chris....

PHP doesn't really support multiple inheritance, but there are some (somewhat messy) ways to implement it. Check out this URL for some examples:

http://www.jasny.net/articles/how-i-php-multiple-inheritance/

Thought they both had useful links. Can't wait to try out traits or maybe some mixins...

Solution 4

The Symfony framework has a mixin plugin for this, you might want to check it out -- even just for ideas, if not to use it.

The "design pattern" answer is to abstract the shared functionality into a separate component, and compose at runtime. Think about a way to abstract out the Invitation functionality out as a class that gets associated with your Message classes in some way other than inheritance.

Solution 5

I'm using traits in PHP 5.4 as the way of solving this. http://php.net/manual/en/language.oop5.traits.php

This allows for classic inheritance with extends, but also gives the possible of placing common functionality and properties into a 'trait'. As the manual says:

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.

Share:
101,628

Related videos on Youtube

Alex Weinstein
Author by

Alex Weinstein

Updated on November 26, 2021

Comments

  • Alex Weinstein
    Alex Weinstein over 2 years

    I'm looking for a good, clean way to go around the fact that PHP5 still doesn't support multiple inheritance. Here's the class hierarchy:

    Message
    -- TextMessage
    -------- InvitationTextMessage
    -- EmailMessage
    -------- InvitationEmailMessage

    The two types of Invitation* classes have a lot in common; i'd love to have a common parent class, Invitation, that they both would inherit from. Unfortunately, they also have a lot in common with their current ancestors... TextMessage and EmailMessage. Classical desire for multiple inheritance here.

    What's the most light-weight approach to solve the issue?

    Thanks!

    • Ondřej Mirtes
      Ondřej Mirtes almost 12 years
      There are not many cases in which inheritance (or even multiple inheritance) is justifiable. Look at SOLID principles. Prefer composition over inheritance.
    • Tyler
      Tyler over 11 years
      @OndřejMirtes what do you mean - "not many cases in which inheritance is justifiable."?
    • Ondřej Mirtes
      Ondřej Mirtes over 11 years
      I mean - inheritance brings more problems than benefits (look at Liskov substitution principle). You can solve almost everything with composition and save a lot of headaches. Inheritance is also static - that means you cannot change what is written already in the code. But compositition can be used at runtime and you can choose implementations dynamically - e. g. reuse the same class with different caching mechanisms.
    • f.ardelian
      f.ardelian almost 11 years
      PHP 5.4 has "traits": stackoverflow.com/a/13966131/492130
    • Sebastian Mach
      Sebastian Mach over 8 years
      @OndřejMirtes: LSP does not inherently conflict with multipe inheritance. E.g., a Triangle can perfectly be a Finite (with function boundingRectangle) as well as a Intersectable (with function intersects) without interfering with LSP at all.
    • gurghet
      gurghet over 7 years
      I would suggest beginners to never use inheritance. In general, the only two situations in which inheritance is allowed are: 1) when building a library, so users write less code and 2) when the project lead demands you use it
  • Alex Weinstein
    Alex Weinstein over 15 years
    Interfaces do not allow for concrete function implementations, so they're not helpful here.
  • Alex Weinstein
    Alex Weinstein over 15 years
    Amazingly extensive answer, thank you! I learned something today!
  • Maria Eugenia D'Amato
    Maria Eugenia D'Amato about 14 years
    ...I know this is a bit old (I was searching to see if PHP had MI... just for curiosity) I don't think this is a good example of the Strategy Pattern. The Strategy Pattern is designed so that you can implement a new "strategy" at any time. The implementation you have provided does not feature such ability. Instead, Message should have the "send" function which calls MessageDispatcher->dispatch() (Dispatcher either a param or member var), and new classes HTMLDispatcher & TextDispatcher will implement "dispatch" in their respective ways (this allows other Dispatchers to do other work)
  • Michał Niedźwiedzki
    Michał Niedźwiedzki about 14 years
    Unfortunately PHP is not great for implementing Strategy pattern. Languages that support method overloading work better here - imagine you have two methods of the same name: dispatch(HTMLMessage $m) and dispatch(TextMessage $) - now in strongly typed language compiler/interpreter would automatically employ the right "strategy" based on type of parameter. Aside from that, I don't think that being open for new strategy implementation is the essence of Strategy Pattern. Sure it's a nice thing to have, but often not a requirement.
  • Craig Lewis
    Craig Lewis about 14 years
    Interfaces do support Multiple Inheritance, unlike classes.
  • user102008
    user102008 almost 13 years
    I think this is feasible. It will combine functionality of multiple classes, but will not actually inherit them (in the sense of instanceof)
  • Olivier Pons
    Olivier Pons almost 10 years
    Your example is very good, and it's a good workaround. But, like all Php stuff, it's always workaround. Getting close to hacking (like traits for example). It's never part of good programming, and adds useless complexity to implement what should be part of a good language. More on this in the second comment.
  • Olivier Pons
    Olivier Pons almost 10 years
    Suppose you have a class Tracing (this is just a sample) where you want to have generic things like debug into a file, send SMS for critical problem and so on. All your classes are children of this class. Now suppose you want to create a class Exception that should have those functions (= child of Tracing). This class must be a child of Exception. How do you design such stuff without multiple inheritance? Yes, you always may have a solution, but you will always get close to hacking. And hacking = expensive solution in the long run. End of story.
  • Phil Lello
    Phil Lello about 9 years
    And this will surely fail to allow overrides as soon as in inner class makes a call to self::<whatever>
  • Admin
    Admin about 9 years
    Olivier Pons, I don't think that subclassing Tracing would be the correct solution for your use case. Something as simple as having an abstract Tracing class with static methods Debug, SendSMS, etc., which can then be called from within any other class with Tracing::SendSMS() etc. Your other classes are not 'types of' of Tracing, they 'use' Tracing. Note: some people may prefer a singleton over static methods; I prefer to use static methods over singletons where possible.
  • Ejaz
    Ejaz almost 6 years
    Olllllllllld answer but the dispatch class having to know the innards of message class is still a no-no. AND adding a new message type will require altering of dispatch class. Strong coupling.
  • l00k
    l00k over 5 years
    Best answer IMO.
  • Jonathan
    Jonathan over 5 years
    Traits are the way to go