×
×

Traits

We'll start from where we left off in the previous article on PHP Interfaces. If you haven't read it, please go and read it now, or get the free eBook on object-oriented programming from the right sidebar (below the content if you are viewing in mobile).

In previous article on PHP Interfaces, we made HondaAccord class implement the ContainerInterface because it has a trunk. As a result, we could use HondaAccord class wherever ContainerInterface is used. But the code looks ugly! Since interfaces can't provide implementation, the methods putItTrunk and takeFromTrunk needed to be implemented in both the classes. This prevents code reuse. That's where traits come to the rescue.

Traits help you embed a set of properties and methods in several independent classes that could be living in different hierarchies. Here is the ContainerTrait trait created in ContainerTrait.php file.

/**
 * ContainerTrait trait.
 */
trait ContainerTrait {
  // Stuff in the trunk.
  public $stuff;
 
  /**
   * Put stuff in trunk.
   *
   * @param mixed $stuff
   *   Stuff to be put in the trunk.
   */
  public function putInTrunk($stuff) {
    $this->stuff = $stuff;
  }
 
  /**
   * Take stuff out from the trunk.
   *
   * @return mixed
   *   Stuff returned from the trunk.
   */
  public function takeFromTrunk() {
    $stuff = $this->stuff;
    unset($this->stuff);
    return $stuff;
  }
}

Now we could modify Container and HondaAccord classes as follows:

require_once 'ContainerInterface.php';
require_once 'ContainerTrait.php';
 
/**
 * Class Container
 */
class Container implements ContainerInterface {
  use ContainerTrait;
}
require_once 'ContainerInterface.php';
require_once 'ContainerTrait.php';

/**
 * Class HondaAccord
 */
class HondaAccord extends Vehicle implements ContainerInterface {
  use ContainerTrait;
}

Notice that in both the files, we are using use ContainerTrait; to include ContainerTrait in each of the classes. Just by using this statement, both HondaAccord and Container class can now use the properties defined in the ContainerTrunk as its own. As an example, add the following code to the end of Vehicle.php.

$yourCar = new HondaAccord('white');
$yourCar->putInTrunk('umbrella');
echo "Things taken out from the trunk: " . $yourCar->takeFromTrunk() . "\n";

On executing the Vehicle.php file, you'll see the following output:

$ php Vehicle.php
Things taken out from the trunk: umbrella

Note that we didn't have to define the methods putInTrunk() and takeFromTrunk(), and the property $stuff in HondaAccord class but we could still use these since HondaAccord class used ContainerTrait. These methods and properties will be available in whichever class we use this trait. This makes for very efficient code reuse.

If you followed everything till this point, then you understand traits well enough to be able to follow Drupal 8 code. PHP spec and rules about traits are quite extensive but those are outside the scope of this post. If you want to read them, go to http://php.net/manual/en/language.oop5.traits.php.

When to use traits?

Use traits when you want a lot of independent classes to have the same method or property without duplicating code in all these classes. In this post, we saw how using ContainerTrait helped us reduce code in Container and HondaAccord classes. Another example is ColorTrait. You could define the property $color and methods getColor() and setColor(). This trait could be used in any class which tries to mimic a real object having color.

Services: 
Drupal Development

Sign up for our weekly newsletter


Add new comment