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

PHP 觀察者模式實作:SPL SplSubject/SplObserver 介面完整範例

     編輯:PHP 綜合知識

示範使用 PHP SPL (Standard PHP Library) 內建 SplSubject 與 SplObserver 介面實作觀察者模式:主題維護狀態、觀察者註冊/移除、狀態變更自動通知所有觀察者。附完整類別代碼與使用範例。

介面定義

interface SplSubject {
    public function attach(SplObserver $observer);
    public function detach(SplObserver $observer);
    public function notify();
}

interface SplObserver {
    public function update(SplSubject $subject);
}

完整實作代碼

<?php
class DemoSubject implements SplSubject {
    private $observers = [];
    private $value;

    public function attach(SplObserver $observer): void {
        $this->observers[] = $observer;
    }

    public function detach(SplObserver $observer): void {
        $key = array_search($observer, $this->observers, true);
        if ($key !== false) unset($this->observers[$key]);
    }

    public function notify(): void {
        foreach ($this->observers as $observer) {
            $observer->update($this);
        }
    }

    public function setValue($value): void {
        $this->value = $value;
        $this->notify(); // 狀態變更即時通知
    }

    public function getValue() {
        return $this->value;
    }
}

class DemoObserver implements SplObserver {
    public function update(SplSubject $subject): void {
        echo '觀察到新值: ' . $subject->getValue() . "\n";
    }
}

// 使用範例
$subject = new DemoSubject();
$observer1 = new DemoObserver();
$observer2 = new DemoObserver();

$subject->attach($observer1);
$subject->attach($observer2);

$subject->setValue(5);  // 輸出兩次:觀察到新值: 5
$subject->setValue(10); // 輸出兩次:觀察到新值: 10

$subject->detach($observer1);
$subject->setValue(20); // 僅輸出一次:觀察到新值: 20
?>

觀察者模式核心角色

角色類別/介面職責
Subject (主題)SplSubject維護狀態、管理觀察者清單、觸發通知
Observer (觀察者)SplObserver實作 update(),接收通知並處理
Client (客戶端)主程式建立主題/觀察者、建立訂閱關係

進階:事件資料傳遞

<?php
class EventSubject implements SplSubject {
    private $observers = [];
    private $eventData = [];

    public function attach(SplObserver $observer) { $this->observers[] = $observer; }
    public function detach(SplObserver $observer) { 
        $k = array_search($observer, $this->observers, true);
        if ($k !== false) unset($this->observers[$k]);
    }
    public function notify() {
        foreach ($this->observers as $obs) $obs->update($this);
    }

    public function trigger(string $event, array $data = []) {
        $this->eventData = ['event' => $event, 'data' => $data, 'time' => time()];
        $this->notify();
    }

    public function getEventData() { return $this->eventData; }
}

class LoggerObserver implements SplObserver {
    public function update(SplSubject $subject) {
        $data = $subject->getEventData();
        error_log("[{$data['time']}] {$data['event']}: " . json_encode($data['data']));
    }
}

class EmailObserver implements SplObserver {
    public function update(SplSubject $subject) {
        $data = $subject->getEventData();
        if ($data['event'] === 'user.register') {
            mail($data['data']['email'], '歡迎註冊', '感謝加入!');
        }
    }
}
?>

適用場景

  • 事件驅動架構:用戶註冊、訂單狀態變更、庫存不足預警。
  • 快取失效:資料更新時通知多個快取層清理。
  • 日誌/監控:業務事件自動記錄、發送告警。
  • UI 綁定:模型變更自動更新多個視圖組件。

SPL vs 手動實作比較

特性SPL 介面手動介面
標準化PHP 官方標準,框架通用專案自定義
型別提示IDE 完整支援需自行定義
擴充性固定方法簽名可彈性調整
相依性零額外相依零相依

最佳實務

  1. 主題狀態變更方法(如 setValue())內部呼叫 notify(),封裝通知邏輯。
  2. 觀察者 update() 應快速返回,耗時操作改用非同步佇列。
  3. 避免循環訂閱(A 觀察 B,B 又觀察 A),導致無限遞迴通知。
  4. 大量觀察者時考慮優先級或分組通知。

使用 SPL 內建介面實作觀察者模式,能獲得標準化、可互操作的事件驅動架構基礎。

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