Overview
Traits let you reuse code in classes that are not part of the same dependency chain.
Traditionally, reusing code from one class in another class has only been possible through inheritance - by creating a class that inherits its methods and properties from a parent class.
But what if you want to reuse code across classes that are not related to each other? That's why PHP added the concept of traits.
A trait looks like a normal PHP class: you give it a name and you add methods, properties, and constants.
Later on, you "include" the trait in other classes through the use keyword to make the trait's methods, properties, and constants automatically available there.
Traits are only meant for grouping methods, properties, and constants together so you can reuse them later. You can't create instances of your Traits. You can only define them and then use them later in other trait or class definitions.
How to define and use a Trait
We declare a trait named Printable with add a method named print().
We then declare a class Dog and "inject" all of methods defined in the Printable trait through the use Printable statement.
How to use multiple Traits
You are not limited to using one single trait. You can use and combine as many traits as you want:
Example 1
You are able to call the like(), share(), and bookmark() methods on the SocialMediaPost object because those methods have been "injected" or "kind of inherited" from the Shareable, Likeable, and Bookmarkable traits that are used by the SocialMediaPost class.
Example 2
Let's extend the previous example a little bit:
We added a User class that uses the Likeable trait, so we will be able to call the like() method on User objects. In other words, we can now like users as well as social media posts.
We added a property of the type User, named $author, to the SocialMediaPost to keep track of who wrote the post.
This example illustrates how traits let you share code across classes that are not related to each other: the SocialMediaPost class and User class do not have a common parent or ancestor, but they can still have certain methods in common.
Difference between Traits and Interfaces
Interfaces and traits are similar in how they are defined and used, but their purpose is different.
Let's compare the two with an example.
If class User implements interface Likeable (which declares a like() method), you can be certain that you can call method like() on any User object.
However, interfaces don't tell you anything about the implementation of like(). The interface doesn't tell you what like() will do; it only tells you that like() will be present.
If class User uses trait Likeable (which declares and implements a like() method), you know that like() will be available in the User class and you know it will be the exact same implementation as the one provided by the trait.
Differences in terms of code reuse
You use interfaces if you want to be sure that classes contain certain methods, named in a certain way, expecting certain parameters, but you don't care about the implementation (inner workings) of those methods.
You use traits if you want to develop a set of fully implemented methods once, and then share them across multiple classes that are not necessarily in the same inheritance chain (otherwise you probably would have used inheritance).
Traits have no impact on polymorphism
Polymorphism makes the type system flexible. If class Dog extends class Animal, and a certain function accepts an object of the type Animal, it will also accept an object of the type Dog, because a Dog is a subtype of Animal.
If a certain function accepts objects that implement a certain interface, that function will accept any type of object as long as it does indeed implement the specified interface. Interfaces are a key aspect of polymorphism.
Traits, however, have no impact on polymorphism. There is no way to specify that your function accepts any type of object as long as it uses a certain trait, for example.
Nested traits
Classes can use traits, and traits themselves can use other traits as well. In other words, it's possible to create traits that are composed of a number of other traits.
Example
→ Compare the following example with example 1.
The output is the same as what example 1 produces, but this time we create a new trait called Actionable, which groups the traits Likeable, Shareable, and Bookmarkable.
We can still use the individual traits Likeable, Shareable, and Bookmarkable elsewhere, or specify all three in the SocialMediaPost class, but we can also make our life easier and use the Actionable trait instead.
Summary
- Traits are collections of methods and properties that can be reused across classes that are not part of the same inheritance chain (the same class hierarchy).
- Traits cannot be instantiated.
- Traits can contain methods, properties, and constants.
- Traits can use other traits.