One of the problems of PHP as a programming language is the fact that you can only have single inheritance. This means a class can only inherit from one other class.
However, a lot of the time it would be beneficial to inherit from multiple classes. For example, it might be desirable to inherit methods from a couple of different classes in order to prevent code duplication.
This problem can lead to class that has a long family history of inheritance which often does not make sense.
In PHP 5.4 a new feature of the language was added known as Traits. A Trait is kind of like a Mixin in that it allows you to mix Trait classes into an existing class. This means you can reduce code duplication and get the benefits whilst avoiding the problems of multiple inheritance.
PHP Traits?
A Trait is simply a group of methods that you want include within another class. A Trait, like an abstract class, cannot be instantiated on it’s own.
An example of a Trait could be:
1 2 3 4 5 6 7 8 |
trait Sharable { public function share($item) { return 'share this item'; } } |
You could then include this Trait within other classes like this:
How do Traits work?
As you can see from the example above, both the Post
and the Comment
objects have the share()
method available despite not having that method defined.
A Trait is basically just a way to “copy and paste” code during run time.
This means the Trait is copied in to the Post
and Comment
classes so when you instantiate a new instance, the share()
method code will be available.
How are Traits different to Abstract classes?
A Trait is different to an Abstract class (What are Abstract classes?) because they do not rely on inheritance.
Imagine if the Post
and the Comment
class had to inherit from a Social
class. We are most likely going to want to do more than just share posts and comments on social media websites, so we’ll probably end up with a complicated inheritance tree like this:
How are Traits different to Interfaces?
Traits kind of look a lot like Interfaces. Both Traits and interfaces are usually simple, concise and not much use without an actual implemented class. However the difference between the two is important.
An interface is a contract that says “this object is able to do this thing”, whereas a Trait is giving the object the ability to do the thing.
For example:
The Sharable
Trait implements the share()
method and the like()
method is implemented in the Post
class.
So as you can see we could type hint the Post
object to see if it is sociable (it implements the Sociable
interface), whilst the Trait defines a reusable method that we can then mix in to other similar classes:
Benefits of Traits?
The benefit of using Traits is that you reduce code duplication whilst preventing complicated class inheritance that might not make sense within the context of your application.
This allows you to define simple Traits that are clear and concise and then mix in that functionality where appropriate.
Drawbacks of Traits?
However with that being said, there are possible drawbacks when using Traits too.
Traits make it very easy to write bloated classes that have too much responsibility. A Trait is essentially a way to “copy and paste” code between classes. By having a way to very simply add another group of methods to a class, it’s very easy to diverge from the single responsibility principle.
Other drawbacks to using Traits are not being able to see all the methods of a class when looking at the source code as well as method conflicts or duplication of logic.
I think Traits, when used correctly, are a fantastic tool to have at our disposal. However, Traits can also be crutch for lazy programming. It’s very easy to just add a Trait to solve your immediate problem. Often composition is the better approach over inheritance or using a Trait.
What are typical situations for using Traits?
So what would be a typical situation when using a Trait would be a good idea?
Well, I think Traits are an excellent way to reuse a chunk of code between a set of similar classes that should not inherit from the same abstract class.
Using the social application from earlier, imagine we had objects for Post
, Photo
, Note
, Message
and Link
. For the most part, these objects are fairly interchangeable within our system as they are typically created and interacted with between users.
However, Post
, Photo
, Note
and Link
are all objects that are publicly shareable between users, whereas Message
objects are private messages that are not made public.