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

PHP 事件機制實現:基於 debug_backtrace 的觀察者模式

     編輯:PHP 相關知識

設計思路

PHP 無原生事件機制,但可通過 `debug_backtrace()` 獲取調用棧,判斷觸發者是否為持有者 (Holder),從而實現「只有持有者能觸發,誰都能監聽」的事件語義。

核心類:Event

<?php
class Event {
    private $callbacks = [];
    private $holder = null;

    public function __construct() {
        $bt = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
        // 調用棧: [0]=__construct, [1]=調用者 (new Event() 所在對象)
        if (count($bt) >= 2 && isset($bt[1]['object'])) {
            $this->holder = $bt[1]['object'];
        }
    }

    // 綁定監聽器:閉包 或 [對象, 方法名]
    public function attach($callable, $method = null) {
        if ($method !== null && is_object($callable)) {
            $this->callbacks[] = [$callable, $method];
        } elseif (is_callable($callable)) {
            $this->callbacks[] = $callable;
        }
    }

    // 觸發事件:僅允許 holder 調用
    public function notify(...$args) {
        $bt = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
        $caller = $bt[0]['object'] ?? null;
        
        if ($this->holder && $caller !== $this->holder) {
            throw new Exception('Event can only be triggered by holder');
        }
        
        foreach ($this->callbacks as $cb) {
            call_user_func_array($cb, $args);
        }
    }
}
?>

使用示例

<?php
class OrderService {
    public $onOrderCreated;
    
    public function __construct() {
        $this->onOrderCreated = new Event(); // $this 自動成為 holder
    }
    
    public function createOrder($data) {
        // 業務邏輯...
        $orderId = 123;
        
        // 觸發事件
        $this->onOrderCreated->notify($orderId, $data);
    }
}

class EmailNotifier {
    public function sendConfirmation($orderId, $data) {
        echo "發送郵件確認訂單 $orderId\n";
    }
}

class SmsNotifier {
    public function sendConfirmation($orderId, $data) {
        echo "發送短信確認訂單 $orderId\n";
    }
}

// 組裝
$orderService = new OrderService();
$orderService->onOrderCreated->attach([new EmailNotifier(), 'sendConfirmation']);
$orderService->onOrderCreated->attach([new SmsNotifier(), 'sendConfirmation']);
$orderService->onOrderCreated->attach(function($id, $data) {
    echo "記錄日誌: 訂單 $id 已創建\n";
});

// 測試
$orderService->createOrder(['product' => 'PHP書籍', 'price' => 99]);

/*
輸出:
發送郵件確認訂單 123
發送短信確認訂單 123
記錄日誌: 訂單 123 已創建
*/
?>

進階:支援優先級與一次性監聽

<?php
class AdvancedEvent {
    private $callbacks = []; // [priority => [callback, once]]
    private $holder;

    public function __construct() {
        $bt = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
        if (count($bt) >= 2) $this->holder = $bt[1]['object'];
    }

    public function attach($callable, $priority = 10, $once = false) {
        $this->callbacks[$priority][] = [$callable, $once];
        ksort($this->callbacks); // 低優先級先執行
    }

    public function notify(...$args) {
        $bt = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
        if ($this->holder && ($bt[0]['object'] ?? null) !== $this->holder) {
            throw new Exception('Unauthorized trigger');
        }
        
        foreach ($this->callbacks as $priority => $list) {
            foreach ($list as $i => [$cb, $once]) {
                call_user_func_array($cb, $args);
                if ($once) unset($this->callbacks[$priority][$i]);
            }
        }
    }
}
?>

性能考量

  • `debug_backtrace()` 較重,高頻調用場景需緩存 holder 或改用靜態綁定
  • 生產環境建議:構造函數傳入 holder 顯式綁定,避免運行時反射
  • 替代方案:Symfony EventDispatcher、Laravel Events、觀察者模式手動管理

總結

利用 `debug_backtrace()` 實現事件持有者驗證,是 PHP 實現領域事件、解耦業務邏輯的輕量級方案。核心優勢:監聽者註冊無限制、觸發權限強管控、代碼侵入性極小。大型項目建議引入成熟事件分發組件。

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