Yiiの根幹を担うCComponent
です。 頭のCってなんだよ気持ち悪い。
CComponent
の挙動がわかるとYiiがよく見えてくるので予備知識としてあるといいかも。
##CComponentとは
Yiiのベースとなるクラスです。framework/base/CComponent.php
に定義されています。Yiiの魔術回路が詰め込まれており、Yiiの中の多くのクラスが継承しています。モデルもARもコントローラーもイベントもコンソールコマンドもYiiにおいてはすべてコンポーネントです。
CComponent
は
- プロパティ
- イベント
- ビヘイビア
に関する機能を持っています。
##プロパティ
例として下記のようなクラスを作ります。
<?php
class Hoge extends CComponent
{
private $name;
public function getName()
{
return $this->name;
}
public function setName($value)
{
$this->name = $value;
}
}
このクラスは以下のように扱えます。
<?php
$hoge = new Hoge;
$hoge->name = 'john';
echo $hoge->name //john
name
はprivateなプロパティですが普通に扱っているように見えます。
実際はCComponent
内のマジックメソッドから、プロパティ名に従ったそれぞれのgetter/setterが呼び出されています。
<?php
$component->fuga // => $component->getFuga()
$component->fuga = $val // => $component->setFuga($val)
これの何が便利なのかというと、通常と同じ簡易なインターフェイスで、getter/setterを定義することができ、処理を挟み込むことができるということです。
あるいは、getterだけしか存在しなければそれはreadOnlyなプロパティとして扱うことができます。
##イベント
CComponent
はイベント機構も備えています。
<?php
class Fuga extends CComponent
{
private $name;
public function getName()
{
$this->raiseEvent('onGetName', new CEvent($this));
return $this->name;
}
public function setName($value)
{
$this->name = $value;
}
public function onGetName($event)
{
$this->raiseEvent('onGetName', $event);
}
}
先ほどのクラスにonGetName()
が追加され、getName()
内raiseEvent()
が呼ばれるようにしました。
<?php
function piyo($event){
echo 'am ';
}
class Poyo{
static public function monyo($event)
{
echo 'a ';
}
}
$hoge = new Hoge();
$hoge->name = 'john';
$hoge->onGetName = function($event){echo "I ";};
$hoge->onGetName = 'piyo'; // => function poyo() return 'am '
$hoge->onGetName = array('Poyo', 'monyo'); // => Poyo::monyo() return 'a '
echo $hoge->name; //I am a john
onGetName
に対してコールバックを連続して代入すると、raiseEvent()
で呼ばれたイベントがすべてコールされます。
Component::onEventName()
がフックポイントになり、発火のタイミングを指定すれば独自イベントも簡単に仕込むことができます。
Yiiで継承されているクラスはいたるところにフックポイントを用意してくれているので、外からの拡張も容易です。
##ビヘイビア
CComponent
はビヘイビアと呼ばれる機構によって多重継承をサポートします
<?php
class Fuga extends CBehavior
{
private $nickName;
public function getNickName()
{
return $this->nickName;
}
public function setNickName($value)
{
$this->nickName = $value;
}
}
ビヘイビアはCBehavior
を継承する必要があります。(正確にはIBehavior
インターフェイスを持っていればいいのです)
<?php
$hoge = new Hoge();
$fugaBehavior = new Fuga();
$hoge->attachBehavior('nick', $fugaBehavior);
$hoge->nickName = 'criff';
echo $hoge->nickName; //criff
echo $hoge->nick->nickName; //criff(上の行と同義)
ビヘイビアをattachBehavior()
でアタッチしてやると、$hoge
から$fuga
のメンバを参照することができます。
内部的には、
- アタッチしたときの名前でビヘイビアを格納 (この場合には
$hoge->nick
) - 呼び出された対象が自身にない場合、格納したビヘイビアのオブジェクトへ投げる
- ビヘイビアに対象があれば呼ぶ。
という動作をしています。
単にコンポーネントにぶら下がったオブジェクトというだけですが、ビヘイビアとして渡すことで、あたかも通常プロパティのように利用することができるのです。
これらの機能が根底にあることで、Yiiは簡易さと拡張性を保持しています。Yiiを使う上で知っておいて損はないです。
特にプロパティは、ARでさらに拡張され、使い慣れてても「あれどっちの呼び出しが優先されるんだっけなー…」と混乱する時があるので細かい挙動を抑えておきたいです。
イベントとビヘイビアは実はそれほど使用頻度高くないですが、便利に使えるケースがあるので、公式のマニュアルなり読み込んでおくと役に立つと思います。
ちなみにコレにもっと細かく書いてあります。のでそちらもどうぞ。