PHP Traits – why is it useful

I know I’m late into the game but I recently found that Traits in PHP is really useful. PHP Traits come in handy if you have some part of a class you wish to re-use in the future in another class, but you don’t want strict inheritance relationship.

What is Traits

PHP Trait defines a code segment that is simply copy-n-pasted into a class at compile time. It can contains variables, constants, methods, static variables and static methods. For detailed definition and behaviour, please read the manual page.

Scenario (when to use)

class_diagram_1
Suppose you have two controllers: UserController, UserApiController, they inherit from BaseAdminController and BaseApiController respectively. Now you want both to support file upload by adding a fileUpload() method. This seems straight-forward to just do this:

You can surely implement the function in both classes by copying the same code, but this will make it hard to maintain, why? what if you want to change it later on? You have to change in both classes. What if someone changed a few lines, but you don’t know and think both are the same and overwritten it? In short, You need to take extra care when you code re-use by copying.

Here is an example using Traits:

Now you just write once, and “use” many (literally).

php_traits

But one might ask: Why don’t you put the common method in the parent class? This is what OOP is for!

The Problem/Limitation of Interface and Abstract classes

The main problem of using Class/Abstract class is, you can only inherit from one parent class. In the above example, UserController and UserApiController inherit from different parent classes (Let’s assume they don’t inherit from 1 common superclass). There seems no simple way to do it in a single inheritance language. Anyway, we should try to do it without using Traits, just to illustrate why Traits should be used.

Try 1: Common superclass

You have to further abstracting the superclasses to, e.g. AbstractUploadController. But here’s the problem, not every BaseAdminController/BaseApiController need upload features, this is not making sense.

<img class="alignnone size-medium wp-image-1400" src="http://madcoda.com/wp-content/uploads/2016/02/class_diagram_2-300×204.png" alt="class_diagram_2" width="300" height="204" srcset="https://madcoda.com/wp-content/uploads/2016/02/class_diagram_2-300×204 this hyperlink.png 300w, https://madcoda.com/wp-content/uploads/2016/02/class_diagram_2.png 752w” sizes=”(max-width: 300px) 100vw, 300px” />

Try 2: Sub-class

If you put fileUpload() in sub-class of the Base controllers, though you will be able to re-use in the future. But in this case this is essentially the same, you still need to copy the code to both “middle parent” controllers.

class_diagram_3

Try 3: Interface + Helper/Utility classes

Interface gives you common interface (contract), but there is no implementation, you still need to copy the code. To solve this, you may add a new helper class, but this add a extra layer of complexity. The helper class also has a drawback, it cannot access the private/protected member methods and variables in the controller. You can add a few getters, but again, it’s complicated.

(There is also another pattern called composition, which I don’t want to mention here)

class_diagram_4

Well, it still not very neat looking, comparing to the code using Traits.

Conclusion

PHP Trait is a great tool to avoid boilerplate code without introducing the strict inheritance relationship or the over-complicated composition pattern, and overcome the limitation of single inheritance. If use well, you can greatly simplify your code and avoid repetition. Hope this post can help you understand more about the awesomeness of PHP!

More to read

See some usage of “Traits” features in other languages

Share your thoughts