コンポーネント

Yii アプリケーションは、一定の仕様に基づいて書かれたオブジェクトであるコンポーネントによって成り立っています。 コンポーネントは CComponent のインスタンスか、派生クラスです。 コンポーネントの使用は大概の場合、プロパティへのアクセスやイベントの発生、ハンドリングを伴います。 基底クラスである CComponent は、どのようにプロパティやイベントの定義を行うかを指定しています。

1. コンポーネントのプロパティの定義と使用

コンポーネントのプロパティはオブジェクトのパブリックなメンバ変数の様なものです。 下の例のように、値を割り当てたり、読み取ったりする事ができます。

$width=$component->textWidth;     // textWidth プロパティを取得
$component->enableCaching=true;   // enableCaching プロパティをセット

コンポーネントのプロパティは、二つの異なる方法によって定義することが出来ます。 一つの方法は、以下の例のように、コンポーネントクラスの中でパブリックなメンバ変数を宣言するという単純な方法です。

class Document extends CComponent
{
    public $textWidth;
}

もう一つの方法は getter と setter を使うものです。こちらの方がより柔軟です。 と言うのは、通常のプロパティに追加して、読出し専用や書込み専用のプロパティを宣言することが出来るからです。

class Document extends CComponent
{
    private $_textWidth;
    protected $_completed=false;
 
    public function getTextWidth()
    {
        return $this->_textWidth;
    }
 
    public function setTextWidth($value)
    {
        $this->_textWidth=$value;
    }
 
    public function getTextHeight()
    {
        // テキストの高さを計算して返す
    }
 
    public function setCompleted($value)
    {
        $this->_completed=$value;
    }
}

上記のコンポーネントは以下のようにして使うことが出来ます。

$document=new Document();
 
// テキストの幅は設定することも読み出すこともできる
$document->textWidth=100;
echo $document->textWidth;
 
// テキストの高さは読み出すことしか出来ない
echo $document->textHeight;
 
// 完了フラグは設定することしかできない
$document->readOnly=true;

コンポーネントのプロパティを読み出そうとするとき、そのプロパティがパブリックなクラスメンバとして定義されていない場合には、 Yii は getter メソッドを使おうと試みます。textWidth に対しては getTextWidth が getter メソッドになります。また、パブリックなクラスメンバとして定義されていないプロパティに対して 値を設定しようとする場合にも同じことが起ります。

getter メソッドはあるけれども setter メソッドは無いという場合、そのコンポーネントプロパティは読出し専用になり、 値を設定しようとすると例外が投げられます。逆の場合は、プロパティは書込み専用になります。

プロパティを定義するのに getter と setter のメソッドを使用することには、 プロパティの読み出しや書き込みの時に追加的なロジック (例えば検証の実行やイベントの発生など) を実行する ことが出来るという利点があります。

注意: getter/setter メソッドで定義されたプロパティとクラスのメンバ変数には少し違いがあります。 前者では、名前の大文字小文字は区別されませんが、後者では大文字小文字が区別されます。

2. コンポーネントのイベント

コンポーネントのイベントは、('event handlers' と呼ばれる) メソッドを値として取る特別なプロパティです。 メソッドをイベントに結びつける (割り当てる) 事によって、イベントが発生した場所から自動的にメソッドが呼ばれることになります。 このように、コンポーネントの振る舞いは、コンポーネントの開発時には予期しなかったであろう動作に改造できます。

コンポーネントのイベントは、on で始まる名前のメソッドを定義する事によって定義されます。 getter/setter メソッドによって定義されるプロパティ名と同様に、イベント名は、大文字小文字を区別しません。 下記のコードは、onClicked イベントを定義しています:

public function onClicked($event)
{
    $this->raiseEvent('onClicked', $event);
}

ここで $event は、CEvent のインスタンスまたはその子クラスで、イベントパラメータを表します。

下記の様にして、このイベントにメソッドを結びつけることが出来ます:

$component->onClicked=$callback;

ここで $callback は、有効な PHP のコールバックを参照します。 コールバックは、グローバル関数でも、クラスメソッドでも構いません。 もしクラスメソッドである場合は、コールバックは array($object,'methodName') という配列として与えられなければなりません。

イベントハンドラのシグネチャ (指示の書式) は下記の様な書式でなければなりません:

function methodName($event)
{
    ......
}

ここで $event は (raiseEvent() のコールによって生じる) イベントを表すパラメータです。 $event パラメータは CEvent のインスタンスか、その派生クラスです。 これには、最低限、誰がイベントを発生させたかの情報が含まれることになります。

イベントハンドラは PHP 5.3 以上でサポートされる匿名関数でも構成できます。例えば、

$component->onClicked=function($event) {
    ......
}

もし今 onClicked() をコールしたとすると、onClicked イベントが (onClicked() の中で) 発生し、 結びついたイベントハンドラが自動的に呼び出されるでしょう。

イベントは複数のハンドラに結びつける事ができます。 イベントが発生した際、ハンドラはイベントに結び付けられた順番で呼び出されます。 もし、あるハンドラが、残りのハンドラが呼び出される事を防ごうとする場合、 $event->handled を true にセットする事が出来ます。

3. コンポーネントのビヘイビア

コンポーネントは mixin パターンをサポートします。 コンポーネントに対して、一つまたは複数のビヘイビアをアタッチすることが可能です。 ビヘイビア のオブジェクトをアタッチされると、コンポーネントはビヘイビアの持つメソッドを '継承' することが出来ます。 ここでは、機能の特化 (つまり通常のクラス継承) ではなく、機能の収集が行なわれます。 コンポーネントには複数のビヘイビアをアタッチできるため、'多重継承' を実現することが出来ます。

ビヘイビアクラスは IBehavior インタフェースを実装する必要があります。ほとんどのビヘイビアは CBehavior ベースクラスから継承して作成することが出来ます。 ビヘイビアを モデル にアタッチする必要がある場合は、CModelBehavior または CActiveRecordBehavior から継承しても構いません。これらの基底クラスは、モデルに固有な付加機能を実装しています。

ビヘイビアを使うには、最初にビヘイビアの attach() メソッドを呼出して、コンポーネントにアタッチしなければなりません。 その後、コンポーネントを通してビヘイビアのメソッドを呼ぶことができます。

// $name はコンポーネントの中でビヘイビアを特定するユニークな名前です
$component->attachBehavior($name, $behavior);
// test() は $behavior のメソッドです
$component->test();

アタッチされたビヘイビアは、コンポーネントの通常のプロパティのようにアクセスすることができます。 たとえば tree という名前のビヘイビアがコンポーネントにアタッチされた場合、 このビヘイビアオブジェクトを以下のようにして参照することができます。

$behavior=$component->tree;
// $behavior=$component->asa('tree');
// と等価

ビヘイビアを一時的に使用不能にして、メソッドがコンポーネントを通して利用できないようにすることが出来ます。 たとえば、

$component->disableBehavior($name);
// 以降の文は例外を起します
$component->test();
$component->enableBehavior($name);
// これで動きます
$component->test();

同じコンポーネントにアタッチされた二つのビヘイビアには同じ名前のメソッドがあるかもしれません。 この場合は最初にアタッチされたビヘイビアのメソッドが優先します。

イベント と組み合せて使われた場合には、ビヘイビアはさらに強力です。 コンポーネントにアタッチされるときに、ビヘイビアは自分のメソッドをコンポーネントのイベントにアタッチすることができます。 そうすることによって、ビヘイビアはコンポーネントの通常の実行フローを監視したり変更したりする機会を得ます。

ビヘイビアのプロパティは、アタッチされているコンポーネントからもアクセス可能です。 このプロパティは、パブリックメンバ変数と、getter/setter で定義されるプロパティの両方を含みます。 例えば、ビヘイビアが xyz というプロパティを持ち、コンポーネント $a にアタッチされている場合、 $a->xyz という式によりビヘイビアのプロパティにアクセスすることができます。

$Id$

Be the first person to leave a comment

Please to leave your comment.