Using Traits in PHP 5.4

Minimizing code duplication through better organization and code reuse is an important goal of Object Oriented Programming. But in PHP it can sometimes be difficult because of the limitations of the single inheritance model it uses; you might have some methods that you would like to use in multiple classes but they may not fit well into the inheritance hierarchy.

Languages like C++ and Python allow us to inherit from multiple classes which solves this problem to some extent, and mixins in Ruby allows us to mix the functionality of one or more classes without using inheritance. But multiple inheritance has issues such as the Diamond Problem problem, and mixins can be a complex mechanism to work with.

In this article I will discuss traits, a new feature introduced in PHP 5.4 to overcome such issues. The concept of traits itself is nothing new to programming and is used in other languages like Scala and Perl. They allows us to horizontally reuse code across independent classes in different class hierarchies.

What a Trait Looks Like

A trait is similar to an abstract class which cannot be instantiated on its own (though more often it’s compared to an interface). The PHP documentation defines traits as follows:

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.

Let’s consider this example:

<?php
class DbReader extends Mysqli
{
}

class FileReader extends SplFileObject
{
}

It’d be a problem if both classes needed some common functionality, for example making both of them singletons. Since PHP doesn’t support multiple inheritance, either each class will have to implement the necessary code to support the Singleton pattern or there will be an inheritance hierarchy that doesn’t make sense. Traits offer a solution to exactly this type of problem.

<?php
trait Singleton
{
    private static $instance;

    public static function getInstance() {
        if (!(self::$instance instanceof self)) {
            self::$instance = new self;
        }
        return self::$instance;
    }
}

class DbReader extends ArrayObject
{
    use Singleton;
}

class  FileReader
{
    use Singleton;
}

The trait Singleton has a straight forward implementation of the Singleton pattern with a static method getInstance() which creates an object of the class using this trait (if it’s not already created) and returns it.

Let’s try to create the objects of these classes using the method getInstance().

<?php
$a = DbReader::getInstance();
$b = FileReader::getInstance();
var_dump($a);  //object(DbReader)
var_dump($b);  //object(FileReader) 

We can see that $a is an object of DbReader and $b is an object of FileReader, but both are now behaving as singletons. The method from Singleton has been horizontally injected to the classes using it.

Traits do not impose any additional semantics on the class. In a way, you can think of it as a compiler-assisted copy and paste mechanism where the methods of the trait is copied into the composing class.

If we were simply subclassing DbReader from a parent with a private $instance property, the property wouldn’t be shown in the dump of ReflectionClass::export(). And yet with traits, there it is!

Class [  class FileReader ] {
  @@ /home/shameer/workplace/php54/index.php 19-22

  - Constants [0] {
  }
  - Static properties [1] {
    Property [ private static $_instance ]
  }
  - Static methods [1] {
    Method [  static public method instance ] {
      @@ /home/shameer/workplace/php54/index.php 6 - 11
    }
  }
  - Properties [0] {
  }
  - Methods [0] {
  }
}

Multiple Traits

So far we have used only one trait with a class, but in some cases we may need to incorporate the functionality of more than one trait.

<?php
trait Hello
{
    function sayHello() {
        echo "Hello";
    }
}

trait World
{
    function sayWorld() {
        echo "World";
    }
}

class MyWorld
{
    use Hello, World;
}

$world = new MyWorld();
echo $world->sayHello() . " " . $world->sayWorld(); //Hello World

Here we have two traits, Hello and World. Trait Hello is only able to say “Hello” and trait World can say “World”. In the MyWorld class we have applied Hello and World so that the MyWorld object will have methods from both traits and be able to say “Hello World”.

Traits Composed of Traits

As the application grows, it’s quite possible that we will have a set of traits which are used across different classes. PHP 5.4 allows us to have traits composed of other traits so that we can include only one instead of a number of traits in all these classes. This lets us rewrite the previous example as follows:

<?php
trait HelloWorld
{
    use Hello, World;
}

class MyWorld
{
    use HelloWorld;
}

$world = new MyWorld();
echo $world->sayHello() . " " . $world->sayWorld(); //Hello World

Here we have created the trait HelloWorld, using traits Hello and World, and included it in MyWorld. Since the HelloWorld trait has methods from the other two traits, it’s just the same as if we had including the two traits in the class ourselves.

Precedence Order

As I’ve already mentioned, traits work as if their methods have been copied and pasted into the classes using them and they are totally flattened into the classes’ definition. There may be methods with the same name in different traits or in the class itself. You might wonder which one will be available in the object of child class.

The precedence order is:

  1. the methods of a trait override inherited methods from the parent class
  2. the methods defined in the current class override methods from a trait

This is made clear in the following example:

<?php
trait Hello
{
    function sayHello() {
        return "Hello";
    }

    function sayWorld() {
        return "Trait World";
    }

    function sayHelloWorld() {
        echo $this->sayHello() . " " . $this->sayWorld();
    }

    function sayBaseWorld() {
        echo $this->sayHello() . " " . parent::sayWorld();
    }
}

class Base
{
    function sayWorld(){
        return "Base World";
    }
}

class HelloWorld extends Base
{
    use Hello;
    function sayWorld() {
        return "World";
    }
}

$h =  new HelloWorld();
$h->sayHelloWorld(); // Hello World
$h->sayBaseWorld(); // Hello Base World

We have a HelloWorld class derived from Base, and both classes have a method named sayWorld() but with different implementations. Also, we have included the trait Hello in the HelloWorld class.

We have two methods, sayHelloWorld() and sayBaseWorld(), the former of which calls sayWorld() which exists in both classes as well as in the trait. But in the output, we can see the one from the child class was invoked. If we need to reference the method from the parent class, we can do so by using the parent keyword as shown in the sayBaseWorld() method.

Conflict Resolution and Aliasing

When using multiple traits there may be a situation where different traits use the same method names. For example, PHP will give a fatal error if you try to run the following code because of conflicting method names:

<?php
trait Game
{
    function play() {
        echo "Playing a game";
    }
}

trait Music
{
    function play() {
        echo "Playing music";
    }
}

class Player
{
    use Game, Music;
}

$player = new Player();
$player->play();

Such trait conflicts aren’t resolved automatically for you. Instead, you must choose which method should be used inside the composing class using the keyword insteadof.

<?php
class Player
{
    use Game, Music {
        Music::play insteadof Game;
    }
}

$player = new Player();
$player->play(); //Playing music

Here we have chosen to use the play() method of the Music trait inside the composing class so the class Player will play music, not a game.

In the above example, one method has been chosen over the other from two traits. In some cases you may want to keep both of them, but still avoiding conflicts. It’s possible to introduce a new name for a method in a trait as an alias. An alias doesn’t rename the method, but offers an alternate name by which it can be invoked. Aliases are created using the keyword as.

<?php
class Player
{
    use Game, Music {
        Game::play as gamePlay;
        Music::play insteadof Game;
    }
}

$player = new Player();
$player->play(); //Playing music
$player->gamePlay(); //Playing a game

Now any object of class Player will have a method gamePlay(), which is the same as Game::play(). Here it should be noted that we have resolved any conflicts explicitly, even after aliasing.

Reflection

The Reflection API is one of the powerful features of PHP to analyze the internal structure of interfaces, classes, and methods and reverse engineer them. And since we’re talking about traits, you might be interested to know about the Reflection API’s support for traits. In PHP 5.4, four methods have been added to ReflectionClass to get information about traits in a class.

We can use ReflectionClass::getTraits() to get an array of all traits used in a class. The ReflectionClass::getTraitNames() method will simply return an array of trait names in that class. ReflectionClass::isTrait() is helpful to check if something is a trait or not.

In the previous section we discussed having aliases for traits to avoid collisions due to traits with the same name. ReflectionClass::getTraitAliases() will return an array of trait aliases mapped to its original name.

Other Features

Apart from the above mentioned, there are other features that makes traits more interesting. We know that in classical inheritance the private properties of a class can’t be accessed by child classes. Traits can access the private properties or methods of the composing classes, and vice versa! Here is an example:

<?php
trait Message
{
    function alert() {
        echo $this->message;
    }
}

class Messenger
{
    use Message;
    private $message = "This is a message";
}

$messenger = new Messenger;
$messenger->alert(); //This is a message

As traits are completely flattened into the class composed of them, any property or method of the trait will become a part of that class and we access them just like any other class properties or methods.

We can even have abstract methods in a trait to enforce the composing class to implement these methods. For example:

<?php
trait Message
{
    private $message;

    function alert() {
        $this->define();
        echo $this->message;
    }
    abstract function define();
}

class Messenger
{
    use Message;
    function define() {
        $this->message = "Custom Message";
    }
}

$messenger = new Messenger;
$messenger->alert(); //Custom Message

Here we have a trait Message with an abstract method define(). It requires all classes which use this trait to implement the method. Otherwise, PHP will give an error saying there is an abstract method which has not been implemented.

Unlike traits in Scala, traits in PHP can have a constructor but it must be declared public (an error will be thrown if is private or protected). Anyway, be cautious when using constructors in traits, though, because it may lead to unintended collisions in the composing classes.

Summary

Traits are one of the most powerful features introduced in PHP 5.4, and I’ve discussed almost all their features in this article. They let programmers reuse code fragments horizontally across multiple classes which do not have to be within the same inheritance hierarchy. Instead of having complex semantics, they provide us with a light weight mechanism for code reuse. Though there are some drawbacks with traits, they certainly can help improve the design of your application removing code duplication and making it more DRY.

Image via Vlue / Shutterstock

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Matt

    Finally! This is almost as good as multiple inheritance (I guess). When I first tried to convert some projects to OOP, I gave up because I knew what I wanted, and after googling I found it was called Multiple Inheritance, and PHP didn’t support it. This looks like “trait” is basically a super-class that any class using it inherits.

    • Shameer C

      Though traits have all the advantages of multiple inheritance, it’s not part of inheritance. It will have only methods that are not a part of the inheritance hierarchy and can be used in multiple classes.

  • Ian

    insteadof? Ugh, that’s a dumb keyword…

    • http://www.phrenzy.org jon

      what would you prefer it to be? it seems to be in keeping with keywords like ‘instanceof’.

      • http://www.maltblue.com Matthew

        I agree. I don’t see anything wrong with insteadof and it’s very much in keeping with instanceof.

        • http://design-forge.ro/ Mihai Stancu

          The InsteadOf keyword is a negation that can be translated as “use the former *NOT* the latter” while the InstanceOf keyword is an affirmation translatable as “the former is an instance of the latter”. Which is my first (slightly personal) beef with that keyword.

          But my biggest grief is that using traits has added a new style of declaring class related things when it could’ve been so simple to keep with many of the consacrated styles while still respecting “the PHP pledge”.

          class Database extends AbstractDatabase implements DatabaseInterface uses GenericDriver, MySQLDriver, PGSQLDriver {
          /* solving a conflict between GenericDriver::quotes, MYSQLDriver::quotes and PGSQLDriver::Quotes */
          public function quotes($string) from MySQLDriver;
          /* changing visibility of method */
          protected function SerialIncrement($string) from PGSQLDriver;
          /* renaming inaccessible methods */
          public function ANSIQuotes($string) from PGSQLDriver::quotes;
          /* all other unconflicting unspeciffied methods do not need to be declared here */
          }

          Above i’ve used the keyword “uses” for which i couldn’t find a replacement. I’ve also used the “from” keyword which could’ve been replaced by “as” but it would’t feel right unless you reversed the roles “PGSQLDriver::quotes AS public function ANSIQuotes()”.

          • http://www.keltdockins.com Kelt

            I think instead of using “insteadof” it should just use the order the traits are ‘used’. So if you do use Game, Music; then Game::play gets called (because it is ‘included’ first). That would do away with the insteadof stuff.

  • http://www.cleverweb.nl Peter Prins

    At the other features example you use “use Sample;” That should be: “use Message;”

    • Shameer C

      Hi Peter
      Thanks for the mention. I’ve corrected it. :)

      • http://www.cleverweb.nl Peter Prins

        Excellent article though :)

  • http://jeungun.wordpress.com Jeune

    Can you unit test traits?

    • Shameer C

      Excellent question. PHPUnit 3.6 supports testing traits through getObjectForTrait(). I didn’t try it though.

  • SMoya

    Thanks for this amazing introduction text!

    • Shameer C

      Hey SMoya, thanks for the comment :)

  • Alex Gervasio

    Good and informative post Shameer, except for the introductory Singleton example (just look at the couple of “getInstance()” calls and you’ll see why it’s not just a whimsy opinion). Singletons are old-fashioned, plagued with lots of issues, ranging from mutable global access, strong coupling, to single responsibility breakage (the list goes on), even in shared-nothing architectures like PHP’s. More clever approaches, such as Dependency Injection help throw away easily Singletons into the trash can, through low-level factories or builders. You still can have one thing of something, without writing a bunch of fuzzy static methods, even if they’re crowded behind a trait.

    If you’re interested in peeking at some nice “Singleton-fighting” writeups, feel free to have a read at this http://sites.google.com/site/steveyegge2/singleton-considered-stupid and this http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/. Not just a few more shallow rants.
    Keep up the good work.

    • Shameer C

      Hi Alex,
      Thanks for the comment. I agree with your opinion. Overusing the Singleton pattern is a bad programming practice. There are some cases we can make use of it without any harm though. I used it in this article just to show an example of using traits still I strongly discourage its usage :) I will go through those links.

  • Amel

    Thanks Shameer
    A well written/structured article.

    • Shameer C

      Hi Amel, Thanks for the comment.

  • http://7php.com Khayrattee Wasseem

    Nicely explained! It’s a GOOD article! I like it!
    As far as this new feature is concerned, I hate the idea of the “insteadof”. It’s kinda lame!

    //Wasseem

  • http://Www.derokorian.com Ryan Pallas

    Excellent article I’ve been waiting for this in php since I started using oop this erl make my next projects much less convoluted. Great explanation!

  • http://www.donnamcmaster.com/ Donna McMaster

    Shameer, thanks for the clear explanation! I have been wishing for multiple inheritance for a project I’m working on, and was not aware of traits. Unfortunately my server is only running PHP 5.2.17 … will have to drop some hints with tech support!

    • Shameer C

      Hey Donna, I’m glad that you liked the post. Though you can start planning your application with the features of PHP 5.4, I don’t think using it in production is a good idea, since its RC6 now.

  • jalal

    nice article! i’ll have to look around for where I can use traits… when 5.4 becomes common place. most of my servers are just up to 5.3 :)

  • Mukke

    Will this work ?
    traitMethod()
    }
    }

    $a = new SubBase();
    $a->printMessage(); //will this show the message
    // i mean can you inherit traits and can you even have protected methods in them ?

  • Muhammad Jehanzeb

    Nice article and very well structured. Good work Shameer!

    • Shameer C

      Thanks Jehanzeb :)

  • Aric Caley

    I can’t seem to find an answer to the question of what happens when trait properties conflict? Can you use the ‘insteadof’ and ‘as’ constructs to resolve a property conflict or are you just stuck?

  • Shameer C

    Hey Aric,
    Me too tried to find an answer but failed. From a basic experiment I concluded that conflict will occur if the property have different default values in traits. However you can assign a different value from a method.

  • Jason

    Awesome. It’s not multiple inheritance and so still wouldn’t allow quite the logical structure that one might look for in certain scenarios, but it’s a massive benefit nonetheless. I’m envisioning how this would improve several projects of mine (mainly in cases where I automatically generate new classes that need some common properties and methods but are otherwise unrelated).

  • Niels Krijger

    Excellent writeup!
    I’m not all that thrilled about traits at all, I could easily see them being overused.
    Nevertheless, I’m looking forward to fixing some ugly duplicates in my projects with these!

  • http://www.drlinux.no/konsulent.php Arne K. Haaje

    Excellent introduction! Looks very useful, though I’m a little worried that exessive use of traits could could lead to maintenance problems. I’m not sure why, but the ghost of large functions.php files is sitting on my shoulder now.. ;)

    • Shameer C

      Glad you liked it. A problem with trait is that the concept is simple and tempting like singletons. It should be used carefully. Otherwise when you comeback after a while you will wonder what the magic is your code doing :D

  • http://PaulANorman.com Paul A. Norman

    Makes php classes very attractive now, well written and really helpful, keep it up!

  • http://objectic.cc/ Niko Kivelä

    Really good article!
    One thing that bothers me. If a trait can define methods, including constructor what happens if a class uses two traits who both define constructor method. Well, you get from that by explicitly defining which one to use by the keyword ‘insteadof’. And second needs to be aliased and I guess, that won’t be a constructor method anymore.
    What’s even more interesting though is that if use define ‘SomeTrait::someMethod as __construct;’, can you define your own constructor method by aliasing some another method from inside a trait what was not intended to be used as a constructor method?

  • Erwin

    Hi Shameer,

    Thanks for the article. One minor comment: in the functions sayHello() and sayWorld() you would probably want to return “Hello” and “World” resp. instead of echoing it.

  • Robin Bankhead

    Great article, look forward to experimenting with traits, BUT:
    Have to say, it’s a poor show that this site’s layout seems to rely so heavily on JavaScript. I arrived (running Firefox 11) with JS disabled and the whole thing was just a mess. For a member of the Sitepoint stable (some of whose excellent books on design and layout I’m happy to own) this is pretty embarrassing I’d say!

    Again, though, top article – thanks.

  • PRASHANT JAIN

    really !! the best explanation of TRAIT class among all , i have visited………thanks for this article …

  • Mithun

    thanks for an excellent article on traits in php.. it really helped..

  • John Doe

    good thanks

  • Peter R

    Big thanks from germany shameer.

    ot: You’re looking like a really funny man! (positive) ;-)

    • Shameer C

      Thanks Peter, glad to see you commented here :)

  • http://www.caspel.it Caspel

    Wow it’s a very simple tutorial of this new feature!
    I will use this feature to simplify my code, expecially for getInstance static method (used often in my class)

  • brio

    Great post, thanks

  • Nickelback

    I have a question:
    class A { function start(){ echo ‘start’; }
    function other() { echo ‘other’; } }
    class B { function getA(){ // can i call a funcs: $a->other() }}
    $a = new A;
    $a->b = new B;
    $a->b->getA();
    —————–
    can i call A function inside method B::getA without passing(b->getA($a) ?

    • Shameer C

      Hey Nickelback,
      I assume that you are trying to get an object of class A with/within getA() method of class B. Its definitely possible by simply creating an object of A inside getA() or make other() a static function. Anyway both of this methods are strongly discouraged. Instead you should be using some injection mechanisms to make object of A available inside class B. Hope this makes sense.

  • Nickelback

    Thanks Shameen C,
    The problem is that if i inject A in B this will be some kind of recursion like:
    A will have B object inside A,
    B will have A object inside B,
    I don’t know if this recursion is OK
    Statics method are not solution too, so i wonder for a good solution.

  • nickelbach

    Can i make conditional chaining in PHP
    $a->b()->get();
    if b() returns null not execute get() ?

    • Shameer C

      Chaining itself can’t be done conditionally, but if you want them you should handle it in logic. Every inner method call should return an object that has the next method to be called.

  • Nickelback

    Yes.
    $a->get(‘name’) // return Nickelback
    $a->get(‘name’)->transform(‘reverse’) // return kcablekciN
    So this is not possible unfortunately!!!

  • jaywant

    i am newbie in web development field. which screw me more, when i heard about all the new things in php. i hope anyone help me to understand traits/and when to use it.