Search code examples
phpinheritancemultiple-inheritancetraits

Using PHP traits to simulate multiple inheritance


For this question I want to present my current design and my idea of using a trait. I would like to know whether my understanding of traits is correct and whether my problem can be solved with another design not involving them.

My current class hierarchy in my framework looks like this:

interface IPage { /* ... */ }
interface IForm extends IPage { /* ... */ }
abstract class AbstractPage implements IPage { /* ... */ }
abstract class AbstractForm extends AbstractPage implements IForm { /* ... */ }

In my applications that are based on the framework I used to have the following:

abstract class AbstractBasePage extends AbstractPage { /* ... */ }

Thus I could add some more stuff to all pages for this particular application that is not common to the framework or other applications. This worked well until I implemented the separation into pages and forms as indicated in the first snippet. Now I ended up with something like this:

abstract class AbstractBasePage extends AbstractPage { /* ... */ }
abstract class AbstractBaseForm extends AbstractForm { /* ... */ }

Let's assume in one application there should be a variable for each page and form that indicates whether something special is displayed in the templates. I would need to introduce the same variable in AbstractBasePage and in AbstractBaseForm. Doing so would force me to keep both snippets in sync which isn't good at all.

I was thinking about creating a trait that exposes variables and functions to both classes which they can in turn refer to in the corresponding functions. Using such a trait would reduce the code duplication at least since I could introduce one publicly accessible method that gets called by both classes but other than that there is a decent abstraction, isn't it?

Is this what traits are supposed to help with? Is there a more suitable approach?


Solution

  • In this particular case I ended up introducing an interface (with functions used by the framework) as a contract that gets extended by IPage. Furthermore I had the particular implementation that is identical for pages and forms in a trait which then in turn got used in the framework classes AbstractPage and AbstractForm.

    The mentioned implementation was inside the framework itself to have a concise design which then in turn is used to do that in my applications as well. For the applications I introduced a trait which holds the variables and functions that are identical in both pages and forms once again which then gets used in the AbstractBasePage and AbstractBaseForm classes.

    For this scenario I needed a what is essentially a language assisted copy and paste feature since I wanted to add something that is not as easily to be done using inheritance but something that can be introduced to classes that are part of different class hierarchies. Therefore I decided to use traits.