PHP traits: share methods between classes without inheritance

PHP traits: share methods between classes without inheritance

PHP 5.4 brought a new construct into the language, called a “trait”. With traits, PHP classes could finally inherit methods and properties from several sources. A direct answer to the single-inheritance problem.

Here is an example:

php
<?php

trait PersonTrait
{

}

As you can see, a trait looks a lot like a class. It is declared with the trait keyword instead. There is a naming convention for traits, which is to add the Trait suffix, so do follow it when you create your own traits and keep the structure clear.

Unlike a class, and this is the thing to remember, a trait cannot extend or implement anything. You cannot instantiate a trait either. Their only purpose is to improve our classes, not to replace them.

Traits can have methods, just like classes. Picture a Person class.

php
<?php
abstract class Person
{

}

Our class, called Person, is an abstract class. That means it is meant to be extended by other classes that represent people.

Now suppose we would like to add a fireball() method. We would like to throw fireballs around, for the magic. We could add something along these lines.

php
<?php
abstract class Person
{
    public function fireball()
    {
        echo 'This Person send a fireball';
    }
}

The problem is that you do not want everyone to be able to throw a fireball, and this is where traits come in.

Traits are perfect for adding methods to an object. We want to add a trait to the humans who have magical powers, so what we are after is a PowerTrait

php
<?php

trait PowerTrait
{
    public function fireball()
    {
        echo 'This person send a fireball.';
    }
}

We have moved the fireball() method into the trait. You will find no other difference here. It also means we can take the method out of Person, like this.

php
<?php
abstract class Animal
{

}

Let us create an Elfe class that inherits from Person.

php
class Elfe extends Person
{
    private $name="Legolas"; // Yes, I know Legolas does not throw fireballs, but he was the only one who came to mind...
}

We have extended Person with the Elfe class, empty though it is for now. Let us say elves can cast spells: we go ahead and use PowerTrait

php
<?php

class Elfe extends Person
{
    use PowerTrait;

private $name="Legolas";
}

The keyword used to add a trait to a class is use, by placing the use PowerTrait; declaration in it

Let us try to call the method inherited from our trait.

php
<?php

// Create a new red panda.
$legolas = new Elfe;

// Stroke the panda.
$legolas->fireball();

We have only used a single trait in this scenario, but you can use as many traits as you need. The following is perfectly possible, for instance.

php
<?php

class Elfe extends Person
{
    use PlayerTrait;
    use PowerTrait;
    use AttributTrait;

private $name="Legolas";
}

Use traits to improve what your classes can do. They are only available on PHP >= 5.4, of course, so keep that in mind.

Precedence

You may be asking yourself the following question. What happens if we extend a class and use a trait that has a method of the same name?

Take this example:

php
<?php
trait TestTrait
{
    public function test()
    {
        echo 'Méthode d\'un trait';
    }
}

class TestClass
{
    public function test()
    {
        echo 'Méthode d\'une classe';
    }
}

Here we have a TestTrait and a TestClass. Both of them have a method called test(), which says where the call came from.

Time to test it:

php
<?php

class Testing extends TestClass
{
    use TestTrait;
}

$test = new Testing;

$test->test();

We have created a class that extends TestClass and uses TestTrait. By calling the shared test() method, we can work out from the output which one takes precedence. Let us give it a go.

code
Méthode d'un trait

we can see that the method from the trait takes precedence over the method in the inherited class.

That means we can use traits to replace behaviour inherited from abstract classes. It is a useful thing to understand if you plan to work with traits, and it is worth knowing when to use a PHP trait as well, another article on the site answers that question.

PHP

Damien Flandrin Web developer since 2010, creator of Gekkode and Email Impact. Every article is tested on a real project before publication. Contact
Newsletter

New tests, tutorials and projects, by e-mail.

Reproducible tests, versioned code, dated results. Never any spam.