Blog/ Traits

By neerav.mehta Tue, 09/22/2015 - 00:21 Comments

We'll start from where we left off in the previous article on [PHP Interfaces](/blog/drupal-8/interface). 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](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.

Ready to get Started?