示範使用 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'], '歡迎註冊', '感謝加入!');
}
}
}
?>
| 特性 | SPL 介面 | 手動介面 |
|---|---|---|
| 標準化 | PHP 官方標準,框架通用 | 專案自定義 |
| 型別提示 | IDE 完整支援 | 需自行定義 |
| 擴充性 | 固定方法簽名 | 可彈性調整 |
| 相依性 | 零額外相依 | 零相依 |
setValue())內部呼叫 notify(),封裝通知邏輯。update() 應快速返回,耗時操作改用非同步佇列。使用 SPL 內建介面實作觀察者模式,能獲得標準化、可互操作的事件驅動架構基礎。