PHP 無原生事件機制,但可通過 `debug_backtrace()` 獲取調用棧,判斷觸發者是否為持有者 (Holder),從而實現「只有持有者能觸發,誰都能監聽」的事件語義。
<?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()` 實現事件持有者驗證,是 PHP 實現領域事件、解耦業務邏輯的輕量級方案。核心優勢:監聽者註冊無限制、觸發權限強管控、代碼侵入性極小。大型項目建議引入成熟事件分發組件。