Multiple Inheritance in PHP

PhpOopInheritance

Php Problem Overview


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!

Php Solutions


Solution 1 - Php

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 - Php

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 - Php

If I can quote Phil in https://stackoverflow.com/questions/7762883/does-anyone-know-how-can-i-extends-2-classes-in-the-class-in-php">this thread...

> PHP, like Java, does not support multiple inheritance. > > Coming in PHP 5.4 will be https://secure.php.net/manual/en/language.oop5.traits.php">**traits**</a> 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 - Php

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 - Php

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.

Solution 6 - Php

It sounds like the decorator pattern may be suitable, but hard to tell without more details.

Solution 7 - Php

This is both a question and a solution....

What about the magical __call(),__get(), __set() methods? I have not yet tested this solution but what if you make a multiInherit class. A protected variable in a child class could contain an array of classes to inherit. The constructor in the multi-interface class could create instances of each of the classes that are being inherited and link them to a private property, say _ext. The __call() method could use the method_exists() function on each of the classes in the _ext array to locate the correct method to call. __get() and __set could be used to locate internal properties, or if your an expert with references you could make the properties of the child class and the inherited classes be references to the same data. The multiple inheritance of your object would be transparent to code using those objects. Also, internal objects could access the inherited objects directly if needed as long as the _ext array is indexed by class name. I have envisioned creating this super-class and have not yet implemented it as I feel that if it works than it could lead to developing some vary bad programming habits.

Solution 8 - Php

I have a couple of questions to ask to clarify what you are doing:

  1. Does your message object just contain a message e.g. body, recipient, schedule time?
  2. What do you intend to do with your Invitation object? Does it need to be treated specially compared to an EmailMessage?
  3. If so WHAT is so special about it?
  4. If that is then the case, why do the message types need handling differently for an invitation?
  5. What if you want to send a welcome message or an OK message? Are they new objects too?

It does sound like you are trying combine too much functionality into a set of objects that should only be concerned with holding a message contents - and not how it should be handled. To me, you see, there is no difference between an invitation or a standard message. If the invitation requires special handling, then that means application logic and not a message type.

For example: a system I built had a shared base message object that was extended into SMS, Email, and other message types. However: these were not extended further - an invitation message was simply pre-defined text to be sent via a message of type Email. A specific Invitation application would be concerned with validation and other requirements for an invite. After all, all you want to do is send message X to recipient Y which should be a discrete system in its own right.

Solution 9 - Php

Same problem like Java. Try using interfaces with abstract functions for solving that problem

Solution 10 - Php

PHP does support interfaces. This could be a good bet, depending on your use-cases.

Solution 11 - Php

How about an Invitation class right below the Message class?

so the hierarchy goes:

Message
--- Invitation
------ TextMessage
------ EmailMessage

And in Invitation class, add the functionality that was in InvitationTextMessage and InvitationEmailMessage.

I know that Invitation isn't really a type of Message, it's more a functionality of Message. So I'm not sure if this is good OO design or not.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAlex WeinsteinView Question on Stackoverflow
Solution 1 - PhpMichał NiedźwiedzkiView Answer on Stackoverflow
Solution 2 - PhpMatthias KestenholzView Answer on Stackoverflow
Solution 3 - PhpSimon EastView Answer on Stackoverflow
Solution 4 - PhpjoelhardiView Answer on Stackoverflow
Solution 5 - PhpMatthewPearsonView Answer on Stackoverflow
Solution 6 - PhpdanioView Answer on Stackoverflow
Solution 7 - PhpRalph RitochView Answer on Stackoverflow
Solution 8 - PhpDaveView Answer on Stackoverflow
Solution 9 - PhpDeeCeeView Answer on Stackoverflow
Solution 10 - PhpCheekysoftView Answer on Stackoverflow
Solution 11 - PhpnubeView Answer on Stackoverflow