3

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 or are traits in this case actually the suggested design?

3
  • 1
    See Best way to do multiple constructors in PHP for a few more ideas on simulating multiple inheritance (my answer there is traits based). – yannis Dec 18 '16 at 13:53
  • @Yannis I assume you'd need to introduce an interface for Student1 and Student2 which acts as a contract to keep it sane especially when working with strict types. Factories seem to be much better in the case of the linked question which don't seem to be applicable to my case. Thanks for your input, though. – Christian Ivicevic Dec 18 '16 at 13:59
  • 1
    Yes, traits are the recommended way to share functionality between otherwise unrelated classes. – Cerad Dec 18 '16 at 19:54
0

There is not enough details in your answer to suggest anything concrete, but I think your class hierarchy goes against ISP. I don't think there is a need for huge abstract classes as well.

Think about creating specialized interfaces for each purpose, following SRP. And then either use traits to put behavior into classes (not recommended unless we know more about your project) or favor composition over inheritance to do the same.

Composition may be used in a variety of ways, I think. But what springs into my mind is creating sets of two interfaces for a specific task. One for a containing class with a single method and another one for a class, implementing that behavior:

  interface ISpecificActionProvider {
    /**
      * @return ISpecificActionHandler
      */
    public function getSpecificActionHandler();
  }

This advice might be good or even bad, depending on your project needs. It is provided to give an idea only.

0

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.