既に定義してあるクラスに別のクラスの関数を利用できるようにしたい。。って場合は通常、デザインパターン的にはコンポジションを使ったりしますが*1、それだと元のクラスに色々と手を加えなくてはならないので、クラス定義後に**後付け**でクラスを拡張できるように(クラス同士をミックスさせるような拡張)する機能がmixinです。

本家ドキュメントから超抜粋

class SomeClass
{
  public function __call($method, $arguments)
  {
    return sfMixer::callMixins();
  }
}

というように、拡張したいクラスには __call() 関数を定義しておく。

あとは、クラスのインスタンス化する前に

sfMixer::register('SomeClass', array('OtherClass', 'getXXX'));
$mySomeClass = new SomeClass();
$mySomeClass->getXXX();

これで、SomeClassにはgetXXX()関数が定義していないので、__call()関数が呼び出されます。そこで、sfMixer::register()で定義した別のクラスの関数を定義してあるので、あたかもSomeClassの関数を呼び出すかのように使えます。まさに混ぜてるという感覚ですね。

__call()関数でなくても、既存関数においても割り込みさせることができます。

class BicycleRider{
  public function climb()
  {
    echo $this->name.' climbs';
    sfMixer::callMixins('slope'); // The climb() method is extendable here
    echo $this->name.' gets to the top';
    sfMixer::callMixins('top'); // And also here
  }

定義した関数と引数の名前は次のようにsfMixer::register()の第1引数で:区切りで指定できるようです。

sfMixer::register('BicycleRider:climb:slope', array('Steroids', 'pass'));
sfMixer::register('BicycleRider:climb:top', array('Steroids', 'pass'));

多様するのは見通しが悪くなるかもしれませんが、プラグインなどで拡張する機能を作るときは重宝するのかな?

*1:違ったっけ?