My Love / Hate Relationship with PHP Traits

Anyone who knows me knows that I am a bit of a stickler when it comes to traditional software design principles. I do believe they lead to outstanding software products when they are followed correctly. This isn’t to say I am not flexible when it comes to new ideas to improve traditional rules. When I saw the introduction of PHP traits in 5.4.0 I was eager to learn all about them and how they worked. Any new trick to simplify my work is always a plus. You may call it “syntax sugar” but as long as it doesn’t break some founding design principle in a willy nilly fashion, I am all over it.

PHP traits, in my opinion, are handy and very flexible. I guess that is the “love” part of my relationship with them. When I am in a rush, it is tricks like this that make things easier for me to get to the point of rolling out the next version of a blockbuster app. However, I feel that traits also meddle with a bit of the inheritance rules that have been proven time and time again. Is it possible to love as well as hate something at the same time?

The Love

Before we go into talking about what I don’t like about traits, let’s take a minute to cover what traits are and some of the things we might like about them. As stated on the PHP website: “Traits are 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.”

In layman’s terms this means that we can define a group of functions on their own and then have several different classes borrow them for their own purposes. These classes might be completely unrelated to one another but all have a need for the same functionality provided by the methods. Perhaps we have several functions related to an engine… like reading its temperature. We have two classes, a plane and a car. Both of these objects act very different but need to “borrow” the temperature reading functions to help monitor their engine’s temperature.

Below we have a simple example of two different classes using a trait called “EngineTools”. This trait has a temperature conversion function. This gives the different classes a way to convert their engine temperatures from a scale of Fahrenheit to Celsius. If we want to add more functionality we can simply add more to the trait definition later thus expanding it. This will give our classes extra abilities without having to mess with the inheritance chain those classes may have. We don’t have to define another class, we don’t have to deal with abstracts or implementing interfaces or inheriting anything. Here is our basic demonstration example…

// Set of traits that we can share with classes. trait EngineTools { // Convert engine temperature to Celsius function currentTempC() { return ($this->engineTemp - 32) * (5/9); } } // Our Plane uses the tools for temperature conversion class Plane { use EngineTools; private $engineTemp; function __construct() { $this->startPlane(); } private function startPlane() { $this->engineTemp = 210; } private function fly() { // Fly } } // Car uses same engine tools for temperature conversion class Car { use EngineTools; private $engineTemp; function __construct() { $this->startCar(); } private function startCar() { $this->engineTemp = 230; } private function drive() { // Drive } } $plane = new Plane(); $car = new Car(); echo $plane->currentTempC() . "<br/>"; echo $car->currentTempC() . "<br/>";

What I love about this concept is that we can write several generic style functions, a library if you will, and have classes use them when they need them. Think of it as “bolt on” technology. Have a plane or a car? Drop in the EngineTools trait and suddenly these classes can do more than before… and we didn’t even really alter the class definition (beyond adding the “use” line). I can see traits as a great way for measurement, calibration, or logging functions to be added to existing classes.

The Hate

Besides traits being a nice mechanism for bolting on functionality to existing structures, they are also going to be a nightmare in the wrong hands. What traits essentially do is offload functionality to yet another, what I will call, entity. These dangers could be some of the following:

An entire class’ abilities are NOT in one location visually.

You alter the trait thinking it will alter one type of class using it, but may introduce problems in another class also using it. Meaning you will have to know all classes using the trait.

Introduces the idea of multiple inheritance ideas which bring with it the need to worry about conflicts in naming. (Yes you can solve it using insteadof, but now you have to worry about that and take precautions like specific naming related to the trait or to use this keyword). This is also related to the deadly diamond of death problem.

The Consensus

I haven’t seen too many people argue one way or the other for/against this feature. In addition, I have not yet seen large scale adoption of it in day to day work. So I guess that means the jury is still out. But my feelings on this feature are mixed and I would recommend using it only in situations where you know the advantages greatly exceed the disadvantages. That is, time and ease of use outweigh unintended naming conflicts or any unforeseen inheritance style side effects.

I do think we should continue to strive for a clear single inheritance design in PHP on new code and use traits as a tool to help grow out functionality for existing complex systems. I would hate to see a feature like this blur the line of inheritance and lead to entities that alter other entities and then scattered throughout a system. Then find that these altering entities are hidden away in some other file which is being included. Hopefully they don’t become a detriment to the future of PHP. What are your thoughts? Do you use them or not? Let us know in the comments below.

Thanks for reading!