Yii框架组件的事件机制原理与用法分析(2)
我们再看一下 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 只包含两个变量 $sender 记录事件触发者, $handled 表示事件是否已经被“解决”。
接着我们再看一下如何给一个组件注册一个事件处理器:
/** * 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 实现的一个链表)创建,然后将事件处理器 add 进这个对象中,这样就可以在 raiseEvent 时遍历所有的事件处理器进行处理了,有点儿类似 jQuery 中注册了多个 click 事件处理器之后,当 click 事件触发时,会按顺序调用之前注册的事件处理器。