一、先看PHP觀察者模式的實現:html
//事件的基類 abstract class BaseEvent { private static $observer; //添加觀察者 public function addObserver($obj) { self::$observer[] = $obj; } //觸發事件、通知全部的觀察者 public function trigger() { foreach(self::$observer as $observer){ $observer->update(); } } } //做爲觀察者要實現的接口 interface ObserverInterface { public function update(); } //具體的一個事件類、要繼承事件基類 class Event extends BaseEvent { public function test() { //執行事件 echo 'test execute success. notify observer <br />'; $this->trigger(); } } //觀察者實現接口 class Observer1 implements ObserverInterface { public function update() { echo 'observer 1 update<br />'; } } class Observer2 implements ObserverInterface { public function update() { echo 'observer 2 update<br />'; } } $e = new Event(); //添加兩個觀察者 $o1 = new Observer1(); $o2 = new Observer2(); $e->addObserver($o1); $e->addObserver($o2); $e->test(); //輸出 //test execute success. notify observer //observer 1 update //observer 2 update
這種實現方式的好處是:數組
很差的地方在於:框架
二、看Yii2.0中event的實現方式this
精簡版:code
//全部想要使用事件功能的類都要繼承 class Components { //保存全部的時間 private $_events = []; //綁定事件 public function on($eventName, $handler, $data) { $this->_events[$eventName][] = [$handler, $data]; } //觸發事件 public function trigger($eventName, $event=null) { foreach($this->_events[$eventName] as $handler){ call_user_func($handler[0], $handler[1]); } } } //郵件類 負責發送郵件(至關於一個觀察者) class Email { public function send($data) { echo 'email send '.$data; echo '<br />'; } } //短信 負責發送短信(至關於一個觀察者) class ShortMessage { public fucntion send($data) { echo 'short message send '.$data; echo '<br />'; } } //評論類 必須繼承自Components class Comment extends Components { const EVENT_SEND_MESSAGE = 'send'; //保存成功觸發發送通知消息事件 public function save() { echo 'comment save success'; echo '<br />'; $this->trigger(self::EVENT_SEND_MESSAGE); } } $comment = new Comment(); $emailHandler = [new Email(), 'send']; $smsHandler = [new ShortMessage(), 'send']; //註冊兩個事件 $comment->on(Comment::EVENT_SEND_MESSAGE, $emailHandler, 'for comment.'); $comment->on(Comment::EVENT_SEND_MESSAGE, $smsHandler, 'for comment.'); //保存評論 $comment->save(); //輸出 comment save success email send for comment. short message send for comment.
對比第一種觀察者模式的實現:server
改進:改進trigger方法htm
//添加Event類 class Event { public $data = null; } //修改trigger方法 public function trigger($eventName, $event=null) { if(is_null($event)){ $event = new Event(); } foreach($this->_events[$eventName] as $handler){ $event->data = $handler[1]; call_user_func($handler[0], $event); } }
修改以後傳遞給事件 處理者。定義統一的一個event以後,全部的事件處理者須要繼承此類,call_user_func傳遞的再也不是data了,而是一個event對象對象
因此Yii框架事件兩種傳遞數據的方式:blog
最終trigger傳遞的事實上是一個event,on傳遞的參數變成了event的data的屬性繼承