Horizontal reusability with traits
By Ryan in object-oriented programming, traits, horizontal reuse, inheritance, composition, php 5.4
The ability for a class to inherit from multiple parents is maligned by many, but can be a good thing in some situations. For those working in PHP, multiple inheritance has never been an option; classes are limited to one parent, though they can implement many other datatypes through the use of interfaces. Interfaces can lead to code duplication in improperly-factored inheritance hierarchies. Even in well-architected hierarchies, multiple classes that implement similar methods can contain a lot of overlap.
To address these concerns, PHP 5.4 includes a new feature called traits which allow us to do something that seems an awful lot like multiple inheritance at first glance. Traits allow PHP classes to be “extended” horizontally, rather than vertically. In other words, we can use traits to write methods once and use them in multiple classes, without the multiple inheritance consequence of adding more explicit type information to the classes we modify.
What traits are
A trait is very similar to a class. It is a collection of methods along with a specific notion of state. Traits use the state of the instance of a class into which they’re inserted; they have access to $this. Their use allows methods to be injected into a class at run time. Traits allow you to define a method and then use it in multiple classes.
There are four main differences between a class and a trait:
- A trait cannot be instantiated
- A trait should avoid the creation of additional state
- A trait cannot implement an interface
but it can extend a classor extend a class - A trait has no specific type
even if it has a parent class
(A note on the above: the first alpha release of PHP 5.4 allowed traits to extend classes. Since there are no useful semantics associated with this feature, it’s been written up as a defect and will be corrected in the next release.)
Number 2 is important, because traits are not intended to be a replacement for classes. As soon as traits contain methods along with properties, they begin to resemble non-instantiable classes. In the current release, properties are allowed within traits, but there is no formal provision for handling such state in the RFC “specification.” It’s probably a good thing to avoid trait properties.
Traits can’t do things that classes do, so why even bother? The good part isn’t their limitation relative to classes, but how they can augment classes’ capabilities. Here are some reasons why traits are even worth bothering with:
- traits allow methods to be written once and injected into multiple, derived classes
- traits allow class functionality to be extended
- traits can be composed—in other words, a trait may consist of other traits
- classes can use multiple traits
- classes can modify trait method visibility but not vice versa
- classes can refer to trait method names using aliases
In a lot of ways, using a trait is like telling the interpreter to copy and paste source code from that trait into any number of classes. Some even refer to it as “compiler-assisted copy and paste.” If that’s how you want to think of it, then go for it. Just keep in mind that it’s not exactly a copy/paste procedure, as I explain below.
Here follow two situations involving code duplication that can be remedied by traits. The first gives a good motivation on traits in general for those who are unfamiliar.
A divergent hierarchy
Say you’re in a situation where you must implement two nephew classes to extend a class hierarchy. For the sake of clarity, imagine that you’re working with a simple hierarchy like the one in the image below. At the head, you’ve got Super, from which all other classes will inherit. Below that, Sub1 and Sub2 contain some functionality useful to you, but both need to be extended. So you create your own subclasses, MySub1 and MySub2.

Code duplication
Somewhere along the way, you realize how great it would be if both classes performed the same action—call it someFunction. Your hierarchy now looks something like the following:

At first, you write someFunction once and stick it in MySub1. After you’re satisfied that it behaves how you expect, you copy and paste its source into MySub2. Your tests pass; then, the full weight of what you’ve just done hits you like a train.
The code on your screen looks something like the following:
You can’t just leave it like this. Code duplication is bad. What’s your next move?
Classical inheritance
Because you already have a well-defined inheritance hierarchy, you should be able to push the duplicated functionality upward to the nearest common ancestor of the two classes. In other words, you’d like to refactor someFunction out of MySub1 and MySub2 and into Super. If you have the ability to modify Super, this is probably the right thing to do.
After the refactoring, your class hierarchy will look like this:

Here’s an example of the code representing this change:
What about in a situation where you are unable to modify the class definitions that you’re using? When working with existing frameworks, this can often be the case. You can’t always just go into a superclass and make changes. This is one situation where it might be nice to use a trait.
Horizontal composition with traits
If we can’t move someFunction up, then let’s move it to the side. Defining a new trait that includes the definition of someFunction—which is common to both MySub1 and MySub2 allows us to sidestep the file permissions issue. Instead, create a chunk of reusable functionality that can be injected into more than one class.
The same problem as above, this time solved by traits, looks like this:

Hierarchicaly, this looks very similar to the original solution. However, we no longer have any duplication because the definition of someFunction has been moved into MyTrait. Now the nephew classes can simply use MyTrait and have someFunction injected into their definitions:
Traits promote horizontal composition because they allow specific pieces of functionality to be injected into any number of classes both without duplication and without respect for the classes’ derived types. Classical inheritance pushes functionality down through a hierarchy, while traits can be used to shove functionality sideways into a hierarchy.
Traits aren’t exactly copypasta
Earlier, I said that you could think of traits as chunks of code that are simply copied and pasted into whatever classes use them. While this is a useful mental model, it’s not exactly right.
To illustrate this, consider the following example which will result in a fatal error when executed. One cannot declare a method prototype with the abstract modifier and then implement that method in the same class. abstract enforces the implementation of some method in a lower class.
If @use@ing a trait were identical to copying and pasting code, then the following gist should fail exactly the same way.
Executing it, however, does not result in a fatal error. Compilation finishes cleanly and "anything" is shown on the screen.
The reason for this is that the abstract keyword means something slightly different in the context of a trait. Classes use abstract to push responsibility down the chain; traits use it to enforce a contract with their includer. This is really straddling the line between “horizontal reusability” and multiple inheritance.
Implementation constraints in traits
Maybe you’ve written a trait that does something with a database connection or file handle. Ideally you would handle some specific, non state-dependent piece of the algorithm with the trait; state-dependent things should be left to classes. To enforce this, you might make a call in your trait to a method that the includer is required to define.
For example, say you call getFileHandle in one of your trait methods. If the class using this trait does not have a getFileHandle method defined somewhere in its hierarchy, you are going to get a runtime fatal error. If instead you modify your trait to include an abstract prototype for this method, you can bubble the runtime error up to a compilation error. PHP simply won’t allow you to use a trait unless you’ve satisfied its method contract. See how similar this is to multiple inheritance?
Distinct hierarchies
There are other situations in which it might make sense to use a trait.
Adding logging capabilities to a class
Adding tracing and logging functionality to a class is very common. Using a trait, we can wrap up all of the initialization and file-handling code into a reusable block and plug it into whatever class we prefer.
Dave Marshall provides another implementation of a Logging trait in this article. The primary differences are that my pseudo Logging trait requires no external state (thanks to the way static local variables work in method bodies) and I skip the detail of providing an actual logger. Details, details!
Turning a class into a Singleton
There are other situations where it is desirable to have horizontal reuse. What if we find that duplication is happening across disjoint hierarchies? It’s not inconceivable that two classes might do something similar or be used in a similar way.
Let’s construct an example where we have multiple classes into which we would like to inject Singleton* functionality:
Parting thoughts
Traits are an exciting new feature coming our way in PHP 5.4. Since 5.4 is still in alpha, it’s difficult to say what exact features will make it to the stable release. There are several quirks and features not mentioned in this article, but my goal was simply to explain the feature at a high enough level that the exact implementation details at release could be easily understood.
Additional resources
- PHP horizontal reuse RFC
- PHP Manual: Traits
- Hacker news discussion about Traits
- HelloWorld with Logging trait
- Why Singletons are Evil