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…

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.

About The Author

Martyr2 is the founder of the Coders Lexicon and author of the new ebooks "The Programmers Idea Book" and "Diagnosing the Problem" . He has been a programmer for over 18 years. He works for a hot application development company in Vancouver Canada which service some of the biggest telecoms in the world. He has won numerous awards for his mentoring in software development and contributes regularly to several communities around the web. He is an expert in numerous languages including .NET, PHP, C/C++, Java and more.

Related Posts

They’re like Ruby’s mixins, which have a very similar role. It does lead to some difficult code reading as you hunt for whichever file has that method. I’ve developed the opinion that if you need Google to find where the method is, something has gone wrong.

I am sure you are not the only one who thinks that. I have seen it happen in many projects where you have to go hunting down some mixin or trait that is in a completely different file. We can only hope that developers do the right thing and keep the parts of classes in the relative general area where they are used. We just have to be cautious on that front. 🙂

As far as “Ruby Mixins”, the big difference is that traits are a purely compile-time construct. You can’t re-bind them at runtime (or instantiation time). If you could (like you can with scala: $obj = new Class with Trait, Trait2), then all bets would be off and it would be incredible. But as it stands, I feel it’s just automated copy-paste which should be treated the same as manual copy-paste (frowned upon)…

Hard to say really but I have seen some different applications use as many as 20-30 different include files, some even more. When you factor in everything from config files, modules, constants, libraries, templates and more you can grow quite quickly. Hopefully I understood your question correctly.

Angelo

Traits are really good, cannot see anything wrong with multiple inheritance or have a library for easy to reuse.

Traits are for small easy objects with a specific use, meaning DO NOT write 1.000.000 lines function and think it will be reusable (in most of the cases it won’t).

If ppl cannot take advantage of traits to work more efficient then they are better off staying at home watching TV all day and claim benefits.

First of congratulations for a good article and starting important discussion. I wouldn’t call Traits a syntax sugar. They are very useful when it’s difficult (or impossible) to pass functionality by inheritance. Saying that this is the only case when I would go for a Trait. If it’s possible to share logic by inheritance that would be my first weapon of choice. To be in a save position I’m trying to use Traits across one namespace but from time to time I break this rule.

Hey thanks for the reply. It sounds like you are taking a reasonable approach. There will certainly be instances where the hierarchy structure won’t accomodate additions/changes and traits are a perfect solution for this.

I tried to get the point across when I mentioned the idea of “bolt on” technology where if things are solidified to the point of no chance of really changing the design to handle the specs, traits give you the perfect chance to add on to it.

As long as you apply them equally and make them easy to find, traits can be awesome. It is part of what I love about them. 🙂

I use quite often languages with true or limited multiple inheritance (Perl, Go, Python, ..) and embrace traits in PHP. The major argument against them, I would subscribe to, is the difficulty of testing (which applies to a degree to abstract classes as well).

To your hate points: Given regular inheritance as “A extends B”, without traits, the first two points apply as well:

* Not all class capabilities are visible in one location (A can what B provides)
* Altering in B effects A (and any other class inheriting from one of those)

The collisions (methods, properties) could have been better resolved (closer to multiple inheritance).. but at least they trow a fatal error, so will probably be quite obvious during testing.

Altogether, I would love to see true multi inheritance in PHP, but settle for traits for now. Sure, this can increase complexity – but if we’d throw any tool out of the box which does that, we’d probably still be writing assembler.

I can’t say I am a huge fan of the idea of multiple inheritance for PHP, just because I know much about the dangers that entails, but you make some good points. Perhaps they will do a better job with handling conflicts. If we all adapt the idea of qualifying the names of our traits we could avoid that problem too.

So for instance if we create a trait where we prefix its methods/properties with a unique name, then the chances of it conflicting in the system might be reduced. Much like you would do with plugin development.

I still think there needs to be work on this feature and I am glad you brought up some of those points. Shows there is work to be done still. 🙂

rolfen

Cant we just use closures? Something like what we do in javasctipt; public myMethod = $someClosure ?

John Pancoast

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.

This point is moot as it applies to any class that can be inherited from and is not exclusive to just traits. This is just a part of OO.

About the Lexicon

The brain child of Martyr2, Dream.In.Code Mentor and veteran programmer, the Coders Lexicon is a website dedicated to the advancement of computer programming and technology. It offers advice, coding resources and references to cover web and desktop development.