What are Traits in PHP and how to use them

Ojo Joseph Oluwaseun
May 22 · 5 min read

Before we talk about what Traits are in PHP, first let's take a look at the PHP inheritance. If you’re familiar with PHP most especially the OOP architecture then no doubt you’re fully cognizant that PHP is one of the languages out there that implement single inheritance. So in a nutshell, PHP doesn’t support multiple inheritances and that’s why a PHP programmer can only inherit a class at a time using the PHP extends keyword.

The image above simply depicts how Class B and Class C are inherited from Class A, and Class D wants to inherit from Class B and Class C. But which version of function A() is going to call when we want to run function A()? Is it from the B or is it from C? This is actually the Multiple inheritance problem and we see why PHP does not support it but there are many cases where you will want to extend to more than one classes for code reusability and to follow the DRY(Don’t repeat yourself) concept.

In PHP one class can only inherit from one other class. The above image shows how Class D inherits from Class C, so function A() will be called from function A of Class C. What if we want to inherit from one or more class? That’s the Single inheritance problem. So how do we solve this, here comes our Hero -> Traits. Traits was introduced in PHP 5.4 and it's so cool and easy to use. Traits is much more similar to a class but it is only for grouping methods in a fine-grained and consistent way. You can’t instantiate a trait like you would do a class, in fact, It is not possible to instantiate a Trait on its own. Lets quickly take a look at how we can implement traits in PHP.

<?php//Mobile.php//First lets create a class and name it Mobileclass Mobile{    public function battery(){        echo 'I am battery';    }}

Next, let’s create another file and call it index.php, inside this file we’ll write a class and call it Galaxy, then we’ll extend it to Mobile.

<?php//index.phprequire_once 'Mobile.php'; //Require the Mobile.php file//Galaxy classclass Galaxy extends Mobile{}$obj = new Galaxy; //Instantiate object
$obj->battery();

Run index.php on the browser or through cmd/terminal using the command php -a then php index.php and you should get I am battery as an output, Cool now let's move forward.

Suppose Galaxy Mobile comes with a new feature of having a laser light. So let’s create a new file and call it Laser.php and in this file create a class and call it Laser and method called power.

<?phpclass Laser{   public function power(){     echo '10 mW';   }}

Now, how do I use this new class of laser in my Galaxy class, normally I will extends but then I can’t extend to more than one class. Now all I have to do is convert the above class to trait using the trait keyword instead of class as in below.

<?phptrait Laser{    public function power(){      echo '10 mW';    }}

Now to make the methods in Laser available in our Galaxy class, we need to ensure it is available in our index.php. Below code shows how to implement the trait we just created

<?php//index.phprequire_once 'Mobile.php'; //Require the Mobile.php file
require_once 'Laser.php'; //Require the Laser.php file
//Galaxy classclass Galaxy extends Mobile{ use Laser; //Use the trait Laser to make methods available}//So now I can use the power method in Trait Laser
$obj = new Galaxy;
$obj->power();
//As well as the methods in Mobile class
$obj->battery();

So we’ve seen how easy it is to use trait, but let’s dive into more features of trait. First, we’ll create a file and call it Projector.php and give it trait Projector.

<?phptrait Projector{  public function range(){

echo '2 m';
}
}

Now, to have more than one trait in our Galaxy class, all we have to do is separate them with a comma (,).

require_once 'Mobile.php'; //Require the Mobile.php file
require_once 'Laser.php'; //Require the Laser.php file
require_once 'Projector.php'; //Require the Laser.php file
//Galaxy classclass Galaxy extends Mobile{use Laser, Projector;}//So now I can use the power method in Trait Laser
$obj = new Galaxy;
$obj->power();
//So now I can use the range method in Trait Projector
$obj->range();
//As well as the methods in Mobile class
$obj->battery();

This is cool but what if we have a method in Projector trait called power and remember that we already have a method named power in our trait Laser, this will apparently confuse PHP and your program will get the fatal error ‘Trait method power cannot be applied because there is a collision…’

trait Projector{    public function range(){
echo '2 m';
}
public function power(){
echo 'I am the power of Projector';
}
}

All we have to do to eradicate this problem is to specify which to use using the insteadof keyword.

<?phprequire_once 'Mobile.php'; //Require the Mobile.php file
require_once 'Laser.php'; //Require the Laser.php file
require_once 'Projector.php'; //Require the Laser.php file
//Galaxy classclass Galaxy extends Mobile{use Laser, Projector{

Laser::power insteadof Projector;
}}//So now I can use the power method in Trait Laser
$obj = new Galaxy;
$obj->power();
//So now I can use the range method in Trait Projector
$obj->range();
//As well as the methods in Mobile class
$obj->battery();

The above code solves the multiple trait methods collision but then what if we still need to use the power method inside Projector what do we do? this is quite simple as well, all we need to do is call the method but assign it to another name as seen below:

<?phpclass Galaxy extends Mobile{use Laser, Projector{

Laser::power insteadof Projector;
Projector::power as Ppower; //this does the trick
}}//So now I can use the two power method in Trait Laser and Projector respectively but I will use the other as Ppower$obj = new Galaxy;
$obj->power();
$obj->Ppower(); //Power method in Projector

I’m sure you can now see how flexible and easy it is to use trait, there are other cool features of trait but this is what you need to get started. Let me know your thoughts in the comment section below, Have a lovely day.

Ojo Joseph Oluwaseun

Written by

I’m Joseph, I have over 4 years of experience building Web Applications, Middleware technology, user interface design and Consulting.