首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 事件分發器模式實作:EventDispatcher 完整原始碼解析

     編輯:PHP 綜合知識

核心類別架構

<?php
// 事件基礎類別
class Event extends stdClass {
    public $target = null;
    public $type = null;
    
    public function __construct($type) {
        $this->type = trim($type);
    }
    public function __toString() { return $this->type; }
}

// 自訂事件類別範例
class MyEvent extends Event {
    const AA = 'aaa';
}

事件分發器抽象類別

abstract class EventDispatcher {
    private $_callbacks = []; // 儲存監聽器
    
    // 附加監聽器:支援函式或類別方法
    public function attach($event, $method, $class = null) {
        $eventStr = (string)$event;
        if ($this->has($event, $method, $class)) return true;
        
        if ($class !== null) {
            $this->_checkMethod($class, $method);
            $this->_callbacks[$eventStr][] = $this->_createMethodListener($eventStr, $class, $method);
        } else {
            $this->_checkFunction($method);
            $this->_callbacks[$eventStr][] = $this->_createFunctionListener($eventStr, $method);
        }
        return true;
    }
    
    // 分發事件
    public function dispatch(Event $event) {
        $event->target = $this;
        $eventStr = (string)$event;
        
        if (isset($this->_callbacks[$eventStr])) {
            foreach ($this->_callbacks[$eventStr] as $listener) {
                if ($listener['object']) {
                    // 類別方法
                    if (is_object($listener['class'])) {
                        $listener['class']->{$listener['method']}($event);
                    } else {
                        call_user_func([$listener['class'], $listener['method']], $event);
                    }
                } else {
                    // 獨立函式
                    $listener['function']($event);
                }
            }
        }
    }
    
    // 移除監聽器
    public function detach($event, $method, $class = null) {
        $eventStr = (string)$event;
        if (!isset($this->_callbacks[$eventStr])) return true;
        if (!$this->has($event, $method, $class)) return true;
        
        $target = $class !== null 
            ? $this->_createMethodListener($eventStr, $class, $method)
            : $this->_createFunctionListener($eventStr, $method);
            
        foreach ($this->_callbacks[$eventStr] as $k => $v) {
            if ($v === $target) {
                unset($this->_callbacks[$eventStr][$k]);
                return true;
            }
        }
        return true;
    }
    
    // 檢查是否已監聽
    public function has($event, $method, $class = null) { /* ... */ }
    
    // 內部輔助方法
    private function _checkMethod($class, $method) { /* ... */ }
    private function _checkFunction($function) { /* ... */ }
    private function _createMethodListener($event, $class, $method) { /* ... */ }
    private function _createFunctionListener($event, $function) { /* ... */ }
}

實際使用範例

<?php
// 發送者:繼承 EventDispatcher
class Ball extends EventDispatcher {
    public function aa() {
        $event = new MyEvent(MyEvent::AA);
        $this->dispatch($event);
    }
}

// 監聽者
class MyTest {
    public function test() {
        $ball = new Ball();
        $ball->attach(MyEvent::AA, 'kk'); // 監聽 aa 事件
        $ball->aa(); // 觸發事件
    }
    public function kk($e) {
        print_r($e); // 處理事件
    }
}

// 執行
try {
    $t = new MyTest();
    $t->test();
} catch (Exception $e) {
    echo $e->getMessage();
}

設計模式優缺點分析

優點缺點/注意
鬆耦合:發送者不需知道監聽者細節除錯困難:調用堆疊不直觀
單一職責:事件邏輯與業務邏輯分離效能開銷:大量事件分發有額外負擔
擴充性強:輕鬆新增/移除監聽者記憶體洩漏風險:忘記 detach 導致物件無法釋放
支援同步/非同步擴充循環事件風險:A 觸發 B,B 再觸發 A

現代 PHP 框架中的事件系統

  • Symfony EventDispatcher:PSR-14 標準實作、優先順序、停止傳播
  • Laravel Events:廣播、隊列監聽者、模型觀察者
  • Yii Event:行為綁定、全域事件
  • PSR-14:EventDispatcherInterface, ListenerProviderInterface 互通標準

新專案建議直接採用成熟框架元件,避免重複造輪子。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved