Mixins in PHP

August 23rd, 2006 by Ivo

One of the concepts I like in Ruby is the concept of 'mixins'. Mixins are a way of 'mixing in' functionality of other classes.

A kind of 'multiple inheritance' like approach, only without actual inheritance. It is similar to interfaces, but interfaces only tell you that an object must implement certain methods, whereas mixins also provide an implementation.

It's a bit hard to describe in a few sentences, but this article and the pragmatic programmer's guide provide a good explanation. But I'll explain the concept with examples below.

In the past, there have been attempts to apply mixins to PHP, but this, back in 2002, required quite some cumbersome code, due to the limitations that PHP4 had at that time. I was wondering if some of PHP5's new features would make this easier, and I managed to create a mixin solution with only a few lines of code.

I'll start with the example that explains the mixins, and after that, I'll show the code that makes it possible. I'll end this post with a few quirks that I encountered, for which I solicit comments to improve the solution.

Classes to mixin

Let's first create some classes that can be mixed in. I've created two, that each implement some display functionality:

 
  class Alertable
  {
    function alert()
    {
      $str = $this->toString();
      echo '<script language="javascript"> alert(''.$str.''); </script>';
    }
  }
 
  class Blinkable
  {
    function blink()
    {
      echo "<blink>".$this->toString()."</blink>";
    }
  }
 

The classes are plain and simple, they have a single method that contains the display logic. One displays a javascript alert, the other displays a blinking text. The first thing to notice here is the call to $this->toString(). There is no method called toString to be found in the class. This is no problem however, because these classes will never be used directly. They will be mixed in, in another class, and $this will point to the instance of that class after being mixed in. We only require the class that mixes in these methods, to have a toString method.

Applying the mixins

Using the mixins is fairly easy:

 
 
  class Hello extends Object
  {
    var $mixins = array("Alertable", "Blinkable");
 
    function toString()
    {
      return "Hello World";
    }
  }
 
  $o = new Hello();
  $o->alert();
  $o->blink();
 

The class Hello extends 'Object', which is a class I wrote. It makes the mixins possible. I'll get to this class later. But let's first look at the effect of applying the mixin.

In the member variable $mixins, I store an array of classes I want to mix in. Then, I create an instance of the class, and I can call alert() and blink() on this object, as if the methods were part of the Hello class. Notice how this looks quite natural? The user of the class won't notice that these methods are actually defined elsewhere, and the developer of the class has an easy way of reusing functionality.

As with inheritance, the methods are overridable: if I would still define a custom alert() method on the Hello class level, this method would be called instead of the mixin. This makes it possible to override parts of the behaviour of the mixins.

How it works

Let's take a look at how this works. The handling of the mixins is done by the Object class. There are two key elements in this solution. First, I make use of the PHP5 magic method '__call' to intercept calls to the objects, and redirect methods to the mixins when necessary. Second, there is a little known, but for mixins very important, feature in PHP, which is explained in the oop basics of the PHP manual:

"$this is a reference to the calling object (usually the object to which the method belongs, but can be another object, if the method is called statically from the context of a secondary object)."

It is a mystery to me why such a confusing concept is the first thing in the 'basics' page, but it is very useful. What this basically means that $this does not necessarily point to the current object, but to the calling object, as long as the method is called statically. You've noticed the $this reference in the Blinkable class above; What I basically did was make sure that the method in the mixin was called statically and voila, $this points to the object that is using the mixin, and the mixed in class code looks very natural, like it is a part of the class it will be mixed into.

Here is the code for my Object class:

 
  /**
    * Generic base class for all objects that want to make use of
    * mixin functionality.
    */
  class Object
  {
    private $_mixinlookup = array();
 
    // The constructor takes a look at the mixins, and creates a lookup
    // array, so upon a method call, we can quickly determine whether the
    // method was mixed in.
    function Object()
    {
      if (is_array($this->mixins))
      {
        foreach($this->mixins as $mixin)
        {
          $methods = get_class_methods($mixin);
          if (is_array($methods))
          {
            foreach($methods as $method) $this->_mixinlookup[$method] = $mixin;
          }
        }
      }
    }
 
    // The __call magic method intercepts any method that does not exist
    // and falls back to one of the mixins if they define the method that is
    // being called.
    function __call($method, $args)
    {
      if (isset($this->_mixinlookup[$method]))
      {
        $elems = array();
        for ($i=0, $_i=count($args); $i<$_i; $i++) $elems[] = "$args[$i]";
        eval("$result = ".$this->_mixinlookup[$method]."::"
            .$method."(".implode(',',$elems).");");
        return $result;
      }
      trigger_error('Call to undefined function '.$method, E_USER_WARNING);
    }
  }
 

This code won't win any performance prizes unfortunately, I had to use eval to dynamically call a static method. Other, more efficient ways should work, but I'll explain why they didn't in the 'Quirks' section below. For many types of application however, the performance penalty is low compared to the power of mixins that you get.

Practical application

Now that I've explained the concept of mixins, and how to make it work in PHP5, I'll give some examples of when to use it. In the real world, you probably won't be using Blinkables, but there is a lot of functionality you can think of that can be mixed in to make classes powerful. For example, if you have a custom Collection class, and you create methods to access all its elements, you could easily create mixins such as Sortable, Enumerable and Iterator. These would add sort, enumeration and iteration methods to your object, without cluttering your object with the code.

Also, whenever you find yourself in a situation where you think you need multiple inheritance, rethink the issue and see if mixins are suitable. Often, you'll find that mixins accomplish exactly what you hoped to accomplish if you had multiple inheritance.

Quirks

I promised to end with some quirks I ran into. You can safely skip this section if you're not interested in gory details. :-)

There was actually only one problem that I encountered that lead me to use eval() for the mixin functionality. I've talked about the $this pseudo-variable and how when called statically, $this points to the calling object. Well, even though this is documented in the first part of the oop basics in the PHP manual, it only works in the case where a method is called with the classname::methodname construction. What I would've liked to use, was call_user_func_array or even better, Andrei's Reflection API, which is much more powerful. With the reflection API, the __call method would've looked like this:

 
 
  function __call($method, $args)
  {
    if (method_exists($this, $method))
    {
      return call_user_func_array(array($this, $method), $args);
    }
    if (isset($this->_mixinlookup[$method]))
    {
      $method = new ReflectionMethod($this->_mixinlookup[$method], $method);
      return $method->invoke(NULL, $args);
    }
    trigger_error('Call to undefined function '.$method, E_USER_WARNING);
  }  
 

This would've been more clean, and probably is faster. Now why doesn't this work? First, to call the method statically, I have to pass NULL as first parameter to invoke. This leads to the following error however:

Non-object passed to Invoke()

The reason is that invoke refuses to call my static method if it has not been defined with the 'static' keyword. Easy, you would think, just make your method truly static:

 
  static function blink()
  {
    echo "<blink>".$this->toString()."</blink>";
  }
 

This leads to a different error:

Fatal error: Using $this when not in object context

This kind of invalidates the whole '$this refers to the calling object' part of the documentation. I'm not sure if I should file a bug report for this, comments are appreciated. (I guess that even if it would not throw an error, it probably wouldn't work anyway because $this would be pointing to the ReflectionMethod object instead of my object instance).

Conclusion

I've tried to demonstrate how the powerful concept of Mixins can be applied in PHP. Since it only takes a few lines of code, I guess it would not be hard to make this a standard feature of the PHP language, so I would really like to see true mixin support in PHP6. But if that doesn't happen, I hope to have provided a fairly easy way to apply the concept to your PHP classes anyway.

Feel free to use the code samples in this post, a reference to the post in your code would be appreciated but is not required.

17 Responses to “Mixins in PHP”

  1. August 25, 2006 at 10:03 am, Peter said:

    Very cool!

    Would it also possible to override the blink method in the class and call the “parent” blink method? E.g.

    [code]
    function blink()
    {
    return ''.parent::blink().'';
    }
    [/code]

    It probably does work, because then the Object’s __call method will probably be called. If this works, it makes it even more cool. :)

  2. August 25, 2006 at 11:41 am, Ants Aasma said:

    If you sacrifice a bit of magic and add a snippet of convention you can do it a lot cleaner. And in a way that’s unlikely to break with future versions. The eval static call hack works pretty much because its an artifact of the implementation that’s unnecessarily difficult to avoid.
    For in-mixable (mixinable?) behaviours just use the convention that the first parameter passed is the current object. Something like this:
    [code]
    class Blinkable {
    function blink($self) {
    echo "".$self->toString()."";
    }
    }
    [/code]

    PS: if (method_exists($this, $method)) should be useless in the context of __call because the condition can never be true. (unless the overloading behaviour is changed in some future version)

    PS2: This commenting system should really escape HTML, not strip it. Stripping it is stupid on more levels than I can be bothered with stating.

  3. August 25, 2006 at 5:26 pm, Ivo Jansch said:

    You are right about the method_exist, I was fooled into thinking __call would intercept any call. (maybe __missing_method would be a clearer name).

    I’ll correct the example, thanks.

    The comment system is default serendipity, I’ll see if I can fix the configuration.

    Your suggestion about passing the object is a valid suggestion, resembling more how proxies and decorators work.

  4. August 27, 2006 at 10:52 am, shadytrees said:

    Comments:
    Perhaps using sprintf and single-quoted strings for the eval string would be clearer and easier to maintain. I.e.

    [code]eval(sprintf('$result = %s::%s(%s);',
    $this->_mixinlookup[$method],
    $method, implode(',', $elems)));[/code]

    You can also use negation on those if conditionals along with return and continue to cut down some of the indentation.

    “andf alls” should be “and falls.”

    Cheers for the neat code.

  5. August 27, 2006 at 11:54 am, Ivo Jansch said:

    Thanks, I’ve corrected the typo. I haven’t changed the eval just yet, as I really would like to find a solution that doesn’t involve eval.

  6. August 29, 2006 at 12:52 am, Daniel said:

    Hello,

    Wouldn’t be faster if you don’t use use var_export for each argument ?
    [code]
    for( $i=0; isset( $args[$i]); $i++)
    $elems[] = '$args[' . $i . ']';
    [/code]
    In any case, the code will be parsed by eval() so there’s no need to serialize or something else the variables.

    sorry my bad english :x

  7. August 29, 2006 at 12:56 am, Ivo Jansch said:

    The reason I used var_export on the variables, is that now it will also work for arrays, which end up as a litteral ‘Array’ if I don’t export them.

  8. August 29, 2006 at 1:08 am, Daniel 'Boo2M0rs0' said:

    No,

    Look my code again.
    The final evaluated code looks like:
    $result = Alertable::alert($args[0],$args[1]); //In the case there is two arguments

    So arrays, objects, ressources and other special types are not converted to string.

  9. August 29, 2006 at 8:24 am, Ivo Jansch said:

    You are right :-) , I misinterpreted your suggestion. This is indeed better as now objects are handled correctly too. I’ve updated the example, thanks!

  10. August 30, 2006 at 9:43 am, Kapitan40 said:

    To avoid the eval
    eval(“$result = “.$this->_mixinlookup[$method].”::”
    .$method.”(“.implode(‘,’,$elems).”);”);

    you may use this:
    $result = call_user_func_array (array ($this->_mixinlookup[$method], $method), $args);

  11. August 30, 2006 at 10:24 am, Ivo Jansch said:

    This is explained in the last part of the article, I cannot use call_user_func_array, as this will not call the method in such a way that $this is still accessible in the mixed in classes.

  12. August 30, 2006 at 12:22 pm, johno said:

    Done something similar here:
    http://www.sitepoint.com/forums/showthread.php?t=332491

  13. September 27, 2006 at 5:31 pm, hoho said:

    This is what i did.

    class Blinkable
    {private $_me;

    function blink()
    {
    echo ““.$this->_me->toString().”“;
    }
    }

    ANd then…

    function __call($method, $args)
    {
    if (isset($this->_mixinlookup[$method]))
    {
    return call_user_func_array(array($this->_mixinlookup[$method])), $method), $args);
    }
    trigger_error(‘Call to undefined function ‘.$method, E_USER_WARNING);
    }

  14. December 09, 2006 at 6:58 am, kaiser said:

    heya. i think i have a reason for one of your quirks–why does the ‘static’ keyword throw the error?

    looking at how you call a superclass (i.e. parent::__construct(), or parent::private_method()), it’s obvious we’re not truly calling a static method: instead, we’re calling an instance method of another class.

    declaring ‘static’, however, is saying that this method should not be associated with an instance. in ruby, though, i think you could get away with that depending on the calling context?

    PHP isn’t built like ruby for sure, which isn’t a bad thing. there’s something to be said about code that isn’t ambigious by convention. you wouldn’t believe how often i flip been @object.column_attribute and @object['column_attribute'] within a rails app.

  15. May 01, 2007 at 5:42 pm, Jasper Bekkers said:

    Too bad we cannot reassign the $this variable anymore, it would have been extremely useful in this particular case. Thankfully we can work around it :) .

    My solution, that doesn’t use eval, is supplied below :) .
    [code]
    class Mixin
    {
    private $me;

    public function setMe($newThis)
    {
    $this->me = $newThis;
    }

    public function __get($key)
    {
    return $this->me->$key;
    }

    public function __call($method, $arguments)
    {
    return call_user_func_array(
    array($this->me, $method),
    $arguments
    );
    }

    public function __set($key, $value)
    {
    $this->me->$key = $value;
    }
    }

    class Object
    {
    private $mixinLookup_ = array();

    public function __construct()
    {
    if(is_array($this->mixins))
    {
    foreach($this->mixins as $mixin)
    {
    $methods = get_class_methods($mixin);
    foreach((array)$methods as $method)
    $this->mixinLookup_[$method] = new $mixin;
    }
    }
    }

    public function __call($method, $arguments)
    {
    if(isset($this->mixinLookup_[$method]))
    {
    $this->mixinLookup_[$method]->setMe($this);
    return call_user_func_array(
    array($this->mixinLookup_[$method], $method),
    $arguments
    );
    }
    }
    }

    class Boldable extends Mixin
    {
    public function bold()
    {
    return "" . $this->toString() . "";
    }
    }

    class Nixim extends Object
    {
    protected $mixins = array("Boldable");

    public function toString()
    {
    return "Nixim";
    }
    }

    $n = new Nixim();
    echo $n->bold();
    [/code]

    PS. Although the post is probably considered old, it still inspired me to write this code (it’s just a couple of minutes old) and share it with you guys :) .

  16. May 15, 2007 at 2:01 pm, Schleicher said:

    I have similar to previous comment Mixin realisation.
    Tested ans deployed in some projects, works well.

    described in my blog:

    http://www.schleicher.ru/blog/183.html

    Sorry, most text in russian, but code is plain…

  17. December 16, 2010 at 7:18 pm, Anthony said:

    Check out ClassMixer (https://github.com/wellspringworldwide/PHP-ClassMixer)
    It gives you mixins and aspect-oriented programming for PHP. The resulting code is very fast, as it does not use eval nor __call magic methods.