在 Hangman 中定義的 GameController 使用到一些屬性 word,可以使用$this->word 的格式來(lái)讀寫(xiě)這個(gè)屬性,但實(shí)際上在 GameController 對(duì)應(yīng)到這個(gè)屬性的方法為
/**
* @return string the word to be guessed. This value is persistent
* during the whole game session.
*/
public function getWord()
{
return $this->getPageState('word');
}
/**
* @param string the word to be guessed. This value is persistent
* during the whole game session.
*/
public function setWord($value)
{
$this->setPageState('word',$value);
}
也就是通過(guò)定義 getWord, setWord 的方式定義一個(gè)支持讀寫(xiě)操作的屬性 word(名字是大小寫(xiě)不敏感的).當(dāng)讀取屬性時(shí),getWord() 就會(huì)被調(diào)用,其返回值則成為屬性值;相似的, 當(dāng)寫(xiě)入屬性時(shí),setWord() 被調(diào)用。如果 setter 方法沒(méi)有定義,則屬性將是只讀的, 如果對(duì)其寫(xiě)入則會(huì)拋出一個(gè)異常。使用 getter 和 setter 方法定義一個(gè)屬性有一個(gè)好處:即當(dāng)讀取或?qū)懭雽傩詴r(shí), 可以執(zhí)行額外的邏輯(例如,執(zhí)行驗(yàn)證,觸發(fā)事件)。 基類 CComponent 除了可以定義屬性外,還支持觸發(fā)事件,和 ASP.Net 中 UI 組件非常類似。
組件事件是一些特殊的屬性,它們使用一些稱作 事件句柄 (event handlers)的方法作為其值。 附加(分配)一個(gè)方法到一個(gè)事件將會(huì)引起方法在事件被喚起處自動(dòng)被調(diào)用。因此, 一個(gè)組件的行為可能會(huì)被一種在部件開(kāi)發(fā)過(guò)程中不可預(yù)見(jiàn)的方式修改。
組件事件以 on 開(kāi)頭的命名方式定義。和屬性通過(guò) getter/setter 方法來(lái)定義的命名方式一樣, 事件的名稱是大小寫(xiě)不敏感的。以下代碼定義了一個(gè) onClicked 事件:
public function onClicked($event)
{
$this->raiseEvent('onClicked', $event);
}
這里作為事件參數(shù)的 $event 是 CEvent 或其子類的實(shí)例。
我們可以附加一個(gè)方法到此 event,如下所示:
$component->onClicked=$callback;
這里的 $callback 指向了一個(gè)有效的 PHP 回調(diào)。它可以是一個(gè)全局函數(shù)也可以是類中的一個(gè)方法。 如果是后者,它必須以一個(gè)數(shù)組的方式提供: array($object,’methodName’).
事件句柄的結(jié)構(gòu)如下:
function methodName($event)
{
......
}
這里的 $event 即描述事件的參數(shù)(它來(lái)源于 raiseEvent() 調(diào)用)。$event 參數(shù)是 CEvent 或其子類的實(shí)例。 至少,它包含了關(guān)于誰(shuí)觸發(fā)了此事件的信息。
從版本 1.0.10 開(kāi)始,事件句柄也可以是一個(gè) PHP 5.3 以后支持的匿名函數(shù)。例如,
$component->onClicked=function($event) {
......
}
如果我們現(xiàn)在調(diào)用 onClicked(),onClicked 事件將被觸發(fā)(在 onClicked() 中), 附屬的事件句柄將被自動(dòng)調(diào)用。
一個(gè)事件可以綁定多個(gè)句柄。當(dāng)事件觸發(fā)時(shí), 這些句柄將被按照它們綁定到事件時(shí)的順序依次執(zhí)行。如果句柄決定組織后續(xù)句柄被執(zhí)行,它可以設(shè)置 $event->handled 為 true。
從版本 1.0.2 開(kāi)始,組件已添加了對(duì) mixin 的支持,并可以綁定一個(gè)或多個(gè)行為。 行為 是一個(gè)對(duì)象,其方法可以被它綁定的部件通過(guò)收集功能的方式來(lái)實(shí)現(xiàn) 繼承(inherited), 而不是專有化繼承(即普通的類繼承).一個(gè)部件可以以’多重繼承’的方式實(shí)現(xiàn)多個(gè)行為的綁定.
行為類必須實(shí)現(xiàn) IBehavior 接口。 大多數(shù)行為可以繼承自 CBehavior 。如果一個(gè)行為需要綁定到一個(gè) 模型, 它也可以從專為模型實(shí)現(xiàn)綁定特性的 CModelBehavior 或 CActiveRecordBehavior 繼承。
要使用一個(gè)行為,它必須首先通過(guò)調(diào)用此行為的 attach() 方法綁定到一個(gè)組件。然后我們就可以通過(guò)組件調(diào)用此行為方法:
// $name 在組件中實(shí)現(xiàn)了對(duì)行為的唯一識(shí)別
$component->attachBehavior($name,$behavior);
// test() 是行為中的方法。
$component->test();
已綁定的行為可以像一個(gè)組件中的普通屬性一樣訪問(wèn)。 例如,如果一個(gè)名為 tree 的行為綁定到了一個(gè)組件,我們就可以通過(guò)如下代碼獲得指向此行為的引用。
$behavior=$component->tree;
// 等于下行代碼:
// $behavior=$component->asa('tree');
行為是可以被臨時(shí)禁止的,此時(shí)它的方法開(kāi)就會(huì)在組件中失效.例如:
$component->disableBehavior($name);
// 下面的代碼將拋出一個(gè)異常
$component->test();
$component->enableBehavior($name);
// 現(xiàn)在就可以使用了
$component->test();
兩個(gè)同名行為綁定到同一個(gè)組件下是有可能的.在這種情況下,先綁定的行為則擁有優(yōu)先權(quán).
當(dāng)和 events, 一起使用時(shí),行為會(huì)更加強(qiáng)大. 當(dāng)行為被綁定到組件時(shí),行為里的一些方法就可以綁定到組件的一些事件上了. 這樣一來(lái),行為就有機(jī)觀察或者改變組件的常規(guī)執(zhí)行流程.
自版本 1.1.0 開(kāi)始,一個(gè)行為的屬性也可以通過(guò)綁定到的組件來(lái)訪問(wèn)。 這些屬性包含公共成員變量以及通過(guò) getters 和/或 setters 方式設(shè)置的屬性。 例如, 若一個(gè)行為有一個(gè) xyz 的屬性,此行為被綁定到組件 $a,然后我們可以使用表達(dá)式 $a->xyz 訪問(wèn)此行為的屬性。