PHP Multiple Inheritance vs. Composition

I’m learning about dealing with PHP’s lack of multiple inheritance. It was really driving me up the wall. I did come up with a solution for multiple inheritance in PHP, but I’ll explain why I don’t recommend using it. Along the way I learned a lot about multiple inheritance vs. composition in PHP. I’ll do my best to sum up both ideas with really simple example code.

The Problem

I have 3 related objects. I grouped them into pages.

  • Page A
  • Page B
  • Page C

Page A and B can both be filtered.

  • Page A is a FilteredPage
  • Page B is a FilteredPage
  • Page C

Page B and Page C have a form that needs to be checked.

  • Page A is a FilteredPage
  • Page B is a FilteredPage and a FormPage
  • Page C is a FormPage

Since Page A isn’t a FormPage, it doesn’t make sense for it to have the functionality of a FormPage. Since Page C isn’t a FilteredPage, it doesn’t make sense for it to have the functionality of a FilteredPage. In my mind, I figured this would work:

  • class Page {}
  • class FilteredPage extends Page {}
  • class FormPage extends Page{}
  • class PageA extends FilteredPage {}
  • class PageB extends FilteredPage, FormPage {}
  • class PageC extends FormPage {}

Unfortunately, the bolded section doesn’t work. PHP doesn’t support multiple inheritance.

The Not Quite Multiple Inheritance Approach – Decorator-ish

I spent some time smoothing walls with my skull, but eventually I came to a working solution. This allowed me to have multiple classes operating on a single class’s properties at runtime, though it doesn’t really represent multiple inheritance.

First off, the base class. It has magic __get and __set methods defined, which I see as the major down-point in this scheme.

The Page definitions.

The base decorator interface that allows for a generic call.

These decorators add properties to the class.

This is how you’d implement it to get the required results. The super nifty thing about this strategy is that you can add the decorator conditionally, and it takes 1 line of code to add or remove a Decorator. There’s nothing hard-coded into the class. The down-sides are many, the major one being that the magic __get and __set methods on the page make error checking a hassle and it’s a much bigger challenge to lock down the scope.

The Composition Approach

The base Page class. Note that there are no magic methods. Also, the abstracted method implies that the subclasses have to do some work.

These are the individual pages. Obviously the features are hard-coded in.

These are the filters. They’re arguably simpler than the not-quite-multiple-inheritance approach, but more obvious is that they have very strict get methods. The interface is super obvious and all interactions with the classes are locked down to what I want.

Finally, this is the implementation of the composition approach. It’s a little annoying that you can’t just call $page_a->getFilters(), since the filters are really just supposed to be related to PageC, but the approach feels much more solid. The other relative downsides are that the FormPage and FilteredPage classes can’t assume that their parent class is a Page – they can only operate in their specific scope, whereas in the previous example the Decorators knew exactly what type of class they were working with.

Conclusion: Multiple Inheritance vs. Composition

For this problem, unless you really really need the dynamic capabilities of the multiple inheritance approach or the superclass scope of the decorators, I’d go with composition. It avoids the trauma that the magic __get and __set methods cause, and it forces a much stricter interface and separation of responsibility.

Happy coding :)

Author Information
  • Nishchay Shah

    Welcome, its 2012. You are discussing things from the last decade, it seems..

    • Fawkes

      Unfortunately I can’t really stand on the shoulders of giants – I’m self-taught and it shows :)

  • dude

    even in 2012, i found your simple explanation of this topic useful and easy to follow. your writing style and approach are applaudable.

  • Sammitch

    All instances of in your code have been replaced with HTML entities, makes it kind of hard to read. Just FYI.

    • troyfawkes

      :/ will fix ASAP, thanks for the heads up :)

    • troyfawkes

      Fixed! Just a checkbox I missed in Crayon.