Traits vs. interfaces

Public Service Announcement:

I want to state for the record that I believe traits are almost always a code smell and should be avoided in favor of composition. It's my opinion that single inheritance is frequently abused to the point of being an anti-pattern and multiple inheritance only compounds this problem. You'll be much better served in most cases by favoring composition over inheritance (be it single or multiple). If you're still interested in traits and their relationship to interfaces, read on ...


Let's start by saying this:

Object-Oriented Programming (OOP) can be a difficult paradigm to grasp. Just because you're using classes doesn't mean your code is Object-Oriented (OO).

To write OO code you need to understand that OOP is really about the capabilities of your objects. You've got to think about classes in terms of what they can do instead of what they actually do. This is in stark contrast to traditional procedural programming where the focus is on making a bit of code "do something."

If OOP code is about planning and design, an interface is the blueprint and an object is the fully constructed house. Meanwhile, traits are simply a way to help build the house laid out by the blueprint (the interface).

Interfaces

So, why should we use interfaces? Quite simply, interfaces make our code less brittle. If you doubt this statement, ask anyone who's been forced to maintain legacy code that wasn't written against interfaces.

The interface is a contract between the programmer and his/her code. The interface says, "As long as you play by my rules you can implement me however you like and I promise I won't break your other code."

So as an example, consider a real-world scenario (no cars or widgets):

You want to implement a caching system for a web application to cut down on server load

You start out by writing a class to cache request responses using APC:

class ApcCacher
{
  public function fetch($key) {
    return apc_fetch($key);
  }
  public function store($key, $data) {
    return apc_store($key, $data);
  }
  public function delete($key) {
    return apc_delete($key);
  }
}

Then, in your HTTP response object, you check for a cache hit before doing all the work to generate the actual response:

class Controller
{
  protected $req;
  protected $resp;
  protected $cacher;

  public function __construct(Request $req, Response $resp, ApcCacher $cacher=NULL) {
    $this->req    = $req;
    $this->resp   = $resp;
    $this->cacher = $cacher;

    $this->buildResponse();
  }

  public function buildResponse() {
    if (NULL !== $this->cacher && $response = $this->cacher->fetch($this->req->uri()) {
      $this->resp = $response;
    } else {
      // Build the response manually
    }
  }

  public function getResponse() {
    return $this->resp;
  }
}

This approach works great. But maybe a few weeks later you decide you want to use a file-based cache system instead of APC. Now you have to change your controller code because you've programmed your controller to work with the functionality of the ApcCacher class rather than to an interface that expresses the capabilities of the ApcCacher class. Let's say instead of the above you had made the Controller class reliant on a CacherInterface instead of the concrete ApcCacher like so:

// Your controller's constructor using the interface as a dependency
public function __construct(Request $req, Response $resp, CacherInterface $cacher=NULL)

To go along with that you define your interface like so:

interface CacherInterface
{
  public function fetch($key);
  public function store($key, $data);
  public function delete($key);
}

In turn you have both your ApcCacher and your new FileCacher classes implement the CacherInterface and you program your Controller class to use the capabilities required by the interface.

This example (hopefully) demonstrates how programming to an interface allows you to change the internal implementation of your classes without worrying if the changes will break your other code.

Traits

Traits, on the other hand, are simply a method for re-using code. Interfaces should not be thought of as a mutually exclusive alternative to traits. In fact, creating traits that fulfill the capabilities required by an interface is the ideal use case.

You should only use traits when multiple classes share the same functionality (likely dictated by the same interface). There's no sense in using a trait to provide functionality for a single class: that only obfuscates what the class does and a better design would move the trait's functionality into the relevant class.

Consider the following trait implementation:

interface Person
{
    public function greet();
    public function eat($food);
}

trait EatingTrait
{
    public function eat($food)
    {
        $this->putInMouth($food);
    }

    private function putInMouth($food)
    {
        // Digest delicious food
    }
}

class NicePerson implements Person
{
    use EatingTrait;

    public function greet()
    {
        echo 'Good day, good sir!';
    }
}

class MeanPerson implements Person
{
    use EatingTrait;

    public function greet()
    {
        echo 'Your mother was a hamster!';
    }
}

A more concrete example: imagine both your FileCacher and your ApcCacher from the interface discussion use the same method to determine whether a cache entry is stale and should be deleted (obviously this isn't the case in real life, but go with it). You could write a trait and allow both classes to use it to for the common interface requirement.

One final word of caution: be careful not to go overboard with traits. Often traits are used as a crutch for poor design when unique class implementations would suffice. You should limit traits to fulfilling interface requirements for best code design.


A trait is essentially PHP's implementation of a mixin, and is effectively a set of extension methods which can be added to any class through the addition of the trait. The methods then become part of that class' implementation, but without using inheritance.

From the PHP Manual (emphasis mine):

Traits are a mechanism for code reuse in single inheritance languages such as PHP. ... It is an addition to traditional inheritance and enables horizontal composition of behavior; that is, the application of class members without requiring inheritance.

An example:

trait myTrait {
    function foo() { return "Foo!"; }
    function bar() { return "Bar!"; }
}

With the above trait defined, I can now do the following:

class MyClass extends SomeBaseClass {
    use myTrait; // Inclusion of the trait myTrait
}

At this point, when I create an instance of class MyClass, it has two methods, called foo() and bar() - which come from myTrait. And - notice that the trait-defined methods already have a method body - which an Interface-defined method can't.

Additionally - PHP, like many other languages, uses a single inheritance model - meaning that a class can derive from multiple interfaces, but not multiple classes. However, a PHP class can have multiple trait inclusions - which allows the programmer to include reusable pieces - as they might if including multiple base classes.

A few things to note:

                      -----------------------------------------------
                      |   Interface   |  Base Class   |    Trait    |
                      ===============================================
> 1 per class         |      Yes      |       No      |     Yes     |
---------------------------------------------------------------------
Define Method Body    |      No       |       Yes     |     Yes     |
---------------------------------------------------------------------
Polymorphism          |      Yes      |       Yes     |     No      |
---------------------------------------------------------------------

Polymorphism:

In the earlier example, where MyClass extends SomeBaseClass, MyClass is an instance of SomeBaseClass. In other words, an array such as SomeBaseClass[] bases can contain instances of MyClass. Similarly, if MyClass extended IBaseInterface, an array of IBaseInterface[] bases could contain instances of MyClass. There is no such polymorphic construct available with a trait - because a trait is essentially just code which is copied for the programmer's convenience into each class which uses it.

Precedence:

As described in the Manual:

An inherited member from a base class is overridden by a member inserted by a Trait. The precedence order is that members from the current class override Trait methods, which in return override inherited methods.

So - consider the following scenario:

class BaseClass {
    function SomeMethod() { /* Do stuff here */ }
}

interface IBase {
    function SomeMethod();
}

trait myTrait {
    function SomeMethod() { /* Do different stuff here */ }
}

class MyClass extends BaseClass implements IBase {
    use myTrait;

    function SomeMethod() { /* Do a third thing */ }
}

When creating an instance of MyClass, above, the following occurs:

  1. The Interface IBase requires a parameterless function called SomeMethod() to be provided.
  2. The base class BaseClass provides an implementation of this method - satisfying the need.
  3. The trait myTrait provides a parameterless function called SomeMethod() as well, which takes precedence over the BaseClass-version
  4. The class MyClass provides its own version of SomeMethod() - which takes precedence over the trait-version.

Conclusion

  1. An Interface can not provide a default implementation of a method body, while a trait can.
  2. An Interface is a polymorphic, inherited construct - while a trait is not.
  3. Multiple Interfaces can be used in the same class, and so can multiple traits.

An interface defines a set of methods that the implementing class must implement.

When a trait is use'd the implementations of the methods come along too--which doesn't happen in an Interface.

That is the biggest difference.

From the Horizontal Reuse for PHP RFC:

Traits is a mechanism for code reuse in single inheritance languages such as PHP. A Trait is intended to reduce some limitations of single inheritance by enabling a developer to reuse sets of methods freely in several independent classes living in different class hierarchies.