本文實(shí)例講述了Yii框架組件的事件機(jī)制原理與用法。分享給大家供大家參考,具體如下:
在深入分析 Yii 的運(yùn)行之前,我們先來看一下 Yii 框架中一個很重要的機(jī)制 - 事件。
Yii 官方參考文檔關(guān)于組件事件的解釋:
=======================================================================
組件事件是一些特殊的屬性,它們使用一些稱作 事件句柄 ( event handlers )的方法作為其值。 附加 ( 分配 ) 一個方法到一個事件將會引起方法在事件被喚起處自動被調(diào)用。因此, 一個組件的行為可能會被一種在部件開發(fā)過程中不可預(yù)見的方式修改。
組件事件以 on 開頭的命名方式定義。和屬性通過 getter/setter 方法來定義的命名方式一樣, 事件的名稱是大小寫不敏感的。以下代碼定義了一個 onClicked 事件 :
1
2
3
4
|
public function onClicked( $event ) { $this ->raiseEvent( 'onClicked' , $event ); } |
這里作為事件參數(shù)的 $event 是 CEvent 或其子類的實(shí)例。
我們可以附加一個方法到此 event ,如下所示 :
1
|
$component ->onClicked= $callback ; |
這里的 $callback 指向了一個有效的 PHP 回調(diào)。它可以是一個全局函數(shù)也可以是類中的一個方法。 如果是后者,它必須以一個數(shù)組的方式提供 : array($object,'methodName').
事件句柄的結(jié)構(gòu)如下:
1
2
3
4
|
function methodName( $event ) { ...... } |
這里的 $event 即描述事件的參數(shù)(它來源于 raiseEvent() 調(diào)用)。 $event 參數(shù)是 CEvent 或其子類的實(shí)例。 至少,它包含了關(guān)于誰觸發(fā)了此事件的信息。
從版本 1.0.10 開始,事件句柄也可以是一個 PHP 5.3 以后支持的匿名函數(shù)。例如,
1
2
3
|
$component ->onClicked= function ( $event ) { ...... } |
如果我們現(xiàn)在調(diào)用 onClicked() , onClicked 事件將被觸發(fā)(在 onClicked() 中), 附屬的事件句柄將被自動調(diào)用。
一個事件可以綁定多個句柄。當(dāng)事件觸發(fā)時, 這些句柄將被按照它們綁定到事件時的順序依次執(zhí)行。如果句柄決定組織后續(xù)句柄被執(zhí)行,它可以設(shè)置 $event->handled 為 true 。
=======================================================================
從這一句開始”我們可以附加一個方法到此 event “,讀者可能 就不知道是什么意思了,于是看一下 CComponent 的源碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
/** * 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 ) { //事件名稱同一小寫化處理 $name = strtolower ( $name ); //先查看成員變量是否有以此命名的事件 if (isset( $this ->_e[ $name ])) { //如果有,這個成員保存的是每一個事件處理器 //以數(shù)組的方式保存 foreach ( $this ->_e[ $name ] as $handler ) { //如果事件處理器是一個字符串,那么就是一個全局函數(shù) if ( is_string ( $handler )) call_user_func( $handler , $event ); //如果不是,那么有可能是一個數(shù)組,該數(shù)組包含一個對象和方法名 //參考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 ; //如果對象是一個對象名 if ( is_string ( $object )) // static method call call_user_func( $handler , $event ); //判斷對象是否有要調(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中沒有這個成員也沒關(guān)系 } |
我們再看一下 CEvent 的代碼( CComponent.php ):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
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 只包含兩個變量 $sender 記錄事件觸發(fā)者, $handled 表示事件是否已經(jīng)被“解決”。
接著我們再看一下如何給一個組件注冊一個事件處理器:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
/** * 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 ])) //新建一個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 ))); } |
由此可以看出,首先獲取事件處理器對象,如果沒有則使用 CList ( Yii 實(shí)現(xiàn)的一個鏈表)創(chuàng)建,然后將事件處理器 add 進(jìn)這個對象中,這樣就可以在 raiseEvent 時遍歷所有的事件處理器進(jìn)行處理了,有點(diǎn)兒類似 jQuery 中注冊了多個 click 事件處理器之后,當(dāng) click 事件觸發(fā)時,會按順序調(diào)用之前注冊的事件處理器。
希望本文所述對大家基于Yii框架的PHP程序設(shè)計(jì)有所幫助。
原文鏈接:https://www.iteye.com/blog/luchuan-910251