Traits and code inclusion

2399 0

PHP allows a class to inherit from only a single parent class, but sometimes we cannot escape the necessity to use code from more than one resource. In these cases, it is common to chain more and more parents. However, this can easily get quite complicated and it is considered a good practice not to exceed beyond an inheritance tree of three generations. Another common practice is to include the code that we would like to share between the classes by using the ‘include’ or ‘require’ PHP built-in functions. This practice, though valid, is hackish by nature.

This is why we need to consider the use of a trait, a new feature that was introduced into PHP version 5.4, as it allows a class to get its code from more than one trait. In fact, it allows a class to use as many traits as it needs.

How do traits work?  

Traits resemble classes in that they group together code elements under a common name, and with the following syntax:

In the example given below, a trait with the name of Price has a method changePriceByDollars() that calculates the new price from the old price and the price change in dollars.

Once we create a trait, we can use it in other classes with the use keyword. In the example given below, both the classes Bmw and Mercedes use the Price trait.

In order to see our code in action, let’s create objects from the classes and then, let’s make use of the changePriceByDollars() method that they got from the trait.

Result:
48000
39900

From this code example, we can understand that we can use the code from the traits inside the classes in pretty much the same way that we can include a block of code into each of the classes.

Is it possible for a class to use more than one trait?

A class can use more than one trait, after all, this is what traits were invented for.

Let’s present to our code another trait with the name of SpecialSell that has a method with the name of annonunceSpecialSell, and make the Mercedes class use both traits.

Result:
39900
Mercedes on special sell

How is a trait different from inheritance?

Traits use a special form of inheritance that enables them to include the code from the traits in the classes.

  • Traits use a form of inheritance that is known as horizontal inheritance in which the code from the trait is included in the classes in which it is used. It is pretty much like using ‘require’ or ‘include’ in the classes to include code from the outside, albeit not hackish.
  • In a trait it is possible to put concrete (real) methods, abstract methods, properties and even constants.
  •  While the same class can use more than one trait, it can only inherit from one class.
  • Traits do not respect the visibility scope, thus allowing a trait’s methods to access private properties and methods in the class that uses them.

In the example given below, the trait’s method changePriceByDollars() is allowed to interact with the private $price property.

Result:
42000
39900

We can see that the trait’s methods has access to private methods within the classes that use them.

What are the advantages of using traits?

Traits allow us to use code from more than one resource in a class and, by doing so, we are able to circumvent the limitation of single class inheritance.

What are the disadvantages of using traits?

When using a trait, we should be on the lookout for code duplication and for naming conflicts that are the result of calling the methods in different traits with the same name.

Traits may be easily misused, resulting in a code that looks like a patchwork, instead of consisting of well-designed and well-thought of class hierarchies through the use of inheritance.

In which scenarios is it preferable to use traits?

In some cases, the use of traits can save the day and prove to be preferable to using inheritance. Think of a scenario in which number of classes implement the same interface and so share its code, but only a few of the classes (and not all of them) need a certain piece of that code. It is reasonable to use inheritance for those methods that are shared by all of the classes, while leaving it better of to traits to hold the methods that are needed in only some of the classes. For example, if we have three classes that inherit the Car interface (Mercedes, Bmw, and Audi) and we need the method that handles special sell to work in only two of these classes (Mercedes and Bmw), we will use a trait so that the code will be shared only by the classes that need it.

The message to take home is that traits are a tool that allows code inclusion from different resources and so could be quite handy when used appropriately

In this article

Join the Conversation



Share