本文實(shí)例講述了Yii框架組件的事件機(jī)制原理與用法。分享給大家供大家參考,具體如下:
在深入分析 Yii 的運(yùn)行之前,我們先來(lái)看一下 Yii 框架中一個(gè)很重要的機(jī)制 - 事件。
Yii 官方參考文檔關(guān)于組件事件的解釋:
=======================================================================
組件事件是一些特殊的屬性,它們使用一些稱作 事件句柄 ( 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 。
=======================================================================
從這一句開(kāi)始”我們可以附加一個(gè)方法到此 event “,讀者可能 就不知道是什么意思了,于是看一下 CComponent 的源碼:
/**
* Raises an event.
* This method represents the happening of an event. It invokes
* all attached handlers for the event.
* @param string the event name
* @param CEvent the event parameter
* @throws CException if the event is undefined or an event handler is invalid.
*/
public function raiseEvent($name,$event)
{
//事件名稱同一小寫(xiě)化處理
$name=strtolower($name);
//先查看成員變量是否有以此命名的事件
if(isset($this->_e[$name]))
{
//如果有,這個(gè)成員保存的是每一個(gè)事件處理器
//以數(shù)組的方式保存
foreach($this->_e[$name] as $handler)
{
//如果事件處理器是一個(gè)字符串,那么就是一個(gè)全局函數(shù)
if(is_string($handler))
call_user_func($handler,$event);
//如果不是,那么有可能是一個(gè)數(shù)組,該數(shù)組包含一個(gè)對(duì)象和方法名
//參考http://php.net/manual/en/function.is-callable.php
else if(is_callable($handler,true))
{
// an array: 0 - object, 1 - method name
list($object,$method)=$handler;
//如果對(duì)象是一個(gè)對(duì)象名
if(is_string($object)) // static method call
call_user_func($handler,$event);
//判斷對(duì)象是否有要調(diào)用的方法
else if(method_exists($object,$method))
$object->$method($event);
else
throw new CException(Yii::t('yii','Event "{class}.{event}" is attached with an invalid handler
"{handler}".',
array('{class}'=>get_class($this), '{event}'=>$name, '{handler}'=>$handler[1])));
}
else
throw new CException(Yii::t('yii','Event "{class}.{event}" is attached with an invalid handler
"{handler}".',
array('{class}'=>get_class($this), '{event}'=>$name, '{handler}'=>gettype($handler))));
// stop further handling if param.handled is set true
//如果想停止繼續(xù)循環(huán)獲取事件的handler
//那么需要設(shè)置event的handled為true
if(($event instanceof CEvent) $event->handled)
return;
}
}
else if(YII_DEBUG !$this->hasEvent($name))
throw new CException(Yii::t('yii','Event "{class}.{event}" is not defined.',
array('{class}'=>get_class($this), '{event}'=>$name)));
//如果_e中沒(méi)有這個(gè)成員也沒(méi)關(guān)系
}
我們?cè)倏匆幌?CEvent 的代碼( CComponent.php ):
class CEvent extends CComponent
{
/**
* @var object the sender of this event
*/
public $sender;
/**
* @var boolean whether the event is handled. Defaults to false.
* When a handler sets this true, the rest uninvoked handlers will not be invoked anymore.
*/
public $handled=false;
/**
* Constructor.
* @param mixed sender of the event
*/
public function __construct($sender=null)
{
$this->sender=$sender;
}
}
CEvent 只包含兩個(gè)變量 $sender 記錄事件觸發(fā)者, $handled 表示事件是否已經(jīng)被“解決”。
接著我們?cè)倏匆幌氯绾谓o一個(gè)組件注冊(cè)一個(gè)事件處理器:
/**
* Attaches an event handler to an event.
*
* An event handler must be a valid PHP callback, i.e., a string referring to
* a global function name, or an array containing two elements with
* the first element being an object and the second element a method name
* of the object.
*
* An event handler must be defined with the following signature,
* pre>
* function handlerName($event) {}
* /pre>
* where $event includes parameters associated with the event.
*
* This is a convenient method of attaching a handler to an event.
* It is equivalent to the following code:
* pre>
* $component->getEventHandlers($eventName)->add($eventHandler);
* /pre>
*
* Using {@link getEventHandlers}, one can also specify the excution order
* of multiple handlers attaching to the same event. For example:
* pre>
* $component->getEventHandlers($eventName)->insertAt(0,$eventHandler);
* /pre>
* makes the handler to be invoked first.
*
* @param string the event name
* @param callback the event handler
* @throws CException if the event is not defined
* @see detachEventHandler
*/
public function attachEventHandler($name,$handler)
{
$this->getEventHandlers($name)->add($handler);
}
/**
* Returns the list of attached event handlers for an event.
* @param string the event name
* @return CList list of attached event handlers for the event
* @throws CException if the event is not defined
*/
public function getEventHandlers($name)
{
if($this->hasEvent($name))
{
$name=strtolower($name);
if(!isset($this->_e[$name]))
//新建一個(gè)CList保存事件的處理器
$this->_e[$name]=new CList;
return $this->_e[$name];
}
else
throw new CException(Yii::t('yii','Event "{class}.{event}" is not defined.',
array('{class}'=>get_class($this), '{event}'=>$name)));
}
由此可以看出,首先獲取事件處理器對(duì)象,如果沒(méi)有則使用 CList ( Yii 實(shí)現(xiàn)的一個(gè)鏈表)創(chuàng)建,然后將事件處理器 add 進(jìn)這個(gè)對(duì)象中,這樣就可以在 raiseEvent 時(shí)遍歷所有的事件處理器進(jìn)行處理了,有點(diǎn)兒類似 jQuery 中注冊(cè)了多個(gè) click 事件處理器之后,當(dāng) click 事件觸發(fā)時(shí),會(huì)按順序調(diào)用之前注冊(cè)的事件處理器。
更多關(guān)于Yii相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Yii框架入門(mén)及常用技巧總結(jié)》、《php優(yōu)秀開(kāi)發(fā)框架總結(jié)》、《smarty模板入門(mén)基礎(chǔ)教程》、《php面向?qū)ο蟪绦蛟O(shè)計(jì)入門(mén)教程》、《php字符串(string)用法總結(jié)》、《php+mysql數(shù)據(jù)庫(kù)操作入門(mén)教程》及《php常見(jiàn)數(shù)據(jù)庫(kù)操作技巧匯總》
希望本文所述對(duì)大家基于Yii框架的PHP程序設(shè)計(jì)有所幫助。
您可能感興趣的文章:- Yii框架學(xué)習(xí)筆記之應(yīng)用組件操作示例
- yii2高級(jí)應(yīng)用之自定義組件實(shí)現(xiàn)全局使用圖片上傳功能的方法
- Yii框架組件和事件行為管理詳解
- Yii擴(kuò)展組件編寫(xiě)方法實(shí)例分析
- yii2行為的方法如何注入到組件類中詳解
- Yii框架響應(yīng)組件用法實(shí)例分析
- Yii框架核心組件類實(shí)例詳解
- PHP的Yii框架中移除組件所綁定的行為的方法
- Yii框架自定義數(shù)據(jù)庫(kù)操作組件示例
- Yii2中組件的注冊(cè)與創(chuàng)建方法
- Yii框架應(yīng)用組件用法實(shí)例分析