Keep Your PHP Code Clean with Traits

In PHP object-oriented programming (OOP), inheritance means a class can only ever have a single parent, thus PHP is called a single inheritance language. Traits however give the ability for a class to inherit one or more sets of functions from different places and are a way around the single inheritance problem. Traits are sometimes referred to as mixins because they aren’t a class, more just a set of functions which get added to whatever uses that trait – and aren’t directly instanciable, so could be described as abstract.

Traits first started as an RFC in 2008, titled: Horizontal Reuse for PHP. And after being approved and developed, traits were first introduced in PHP 5.4 when it was released in 2012.

How to use a trait#

Traits can be defined, similarly to a class, by using the trait keyword just before the trait’s name. They can then be added to a class with a ‘use’ statement – similar, but not the same as importing a class below the namespace. This differs from traditional inheritance in that it does not use the ‘extends’ keyword. Here’s an example:

trait Bark
{
    public function say()
    {
        return "Woof";
    }
}

class Dog
{
    use Bark;
}

$dog = new Dog();
echo $dog->say(); // == "Woof"

You might be wondering at this stage, if it is possible to inherit functions from multiple places then, if a function gets called the same thing in multiple traits and they both get added, which one will get run? Well traits work in the order in which they are called, by order of precedence, so the trait which gets included first will gain priority of other functions/methods stored in subsequent traits.

As well as having a method in different traits called the same thing, what if a method already exists in the class? Well the class is considered to have priority, so if the method exists in the class this method will run, not the method in any traits. Having said this, traits have priority of methods within a class’ parent.

$this > traits > parent

The Downsides#

As @bitfalls pointed out on twitter, there is much skepticism and negativity around traits within the PHP community, and they have been described as a possible ‘next most abused feature’ within PHP. Quite rightly in my opinion, as with anything, there is a time and a place to use traits and there is always a danger of over-using them.

One of the problems associated with multiple-inheritance is the ‘deadly diamond of death‘, which basically leave ambiguity as to where a method is inherited from and which method should be run. Traits, by allowing this multiple inheritance, open the door to this problem.

Uses for Traits#

Having run through some of the positives and negatives on traits, we will just take a quick look on how you can take them further. Traits in my opinion differ from classes in that classes should be used to describe to ‘what’ your software is being used for, Animals, parcels, people – you name it. Traits on the other hand should be used to describe ‘how’ it should work, like the use of a design pattern.

The particular use case for traits I have come across lately, is within testing suites. Traits allow you to turn on and off ‘options’ for each particular test class. This is commonly done within Laravel framework with use of ‘WithoutMiddleware’ and ‘DatabaseTransactions‘ to change the behavior of the test.

My opinion is that these are just some good examples because they describe more of the ‘how’ than the ‘what’.