PHP觀察者模式與Yii2.0事件

一、先看PHP觀察者模式的實現:html

  • 想要使用事件、必須實現事件的基類、統一的addObserver和trigger方法
  • 定義統一接口、全部的觀察者都要實現此接口
//事件的基類
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

這種實現方式的好處是:數組

  • 直接addObserver就好、事件完成以後直接觸發就好了、由於觀察者實現了統一的接口

很差的地方在於:框架

  • 每一個觀察者都要去實現接口
  • 若是觸發的時候要傳遞數據、就只能修改接口中的定義、而且還要修改BaseEvent中的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

  • 不須要每一個觀察者都實現統一的接口
  • 利用call_user_func能夠之間傳遞數組:包括對象實例和對應的方法

改進:改進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

  • 在on綁定的時候
  • 在trigger的時候

最終trigger傳遞的事實上是一個event,on傳遞的參數變成了event的data的屬性繼承

原文連接:http://www.cnblogs.com/skyfynn/p/8891008.html

相關文章
相關標籤/搜索