ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] ## 示例 ### 概念示例 <details> <summary>main.php</summary> ``` <?php class Subject implements SplSubject { /** * @var int For the sake of simplicity, the Subject's state, essential to * all subscribers, is stored in this variable. */ public $state; /** * @var SplObjectStorage */ private $observers; public function __construct() { $this->observers = new SplObjectStorage(); } /** * @param SplObserver $observer */ public function attach(SplObserver $observer): void { echo "Subject: Attached an observer.\n"; $this->observers->attach($observer); } /** * @param SplObserver $observer */ public function detach(SplObserver $observer): void { $this->observers->detach($observer); echo "Subject: Detached an observer.\n"; } public function notify(): void { echo "Subject: Notifying observers...\n"; foreach ($this->observers as $observer) { $observer->update($this); } } public function someBusinessLogic(): void { echo "\nSubject: I'm doing something important.\n"; $this->state = rand(0, 10); echo "Subject: My state has just changed to: {$this->state}\n"; $this->notify(); } } class ConcreteObserverA implements SplObserver { public function update(\SplSubject $subject): void { if ($subject->state < 3) { echo "ConcreteObserverA: Reacted to the event.\n"; } } } class ConcreteObserverB implements \SplObserver { public function update(\SplSubject $subject): void { if ($subject->state == 0 || $subject->state >= 2) { echo "ConcreteObserverB: Reacted to the event.\n"; } } } $subject = new Subject(); $o1 = new ConcreteObserverA(); $subject->attach($o1); $o2 = new ConcreteObserverB(); $subject->attach($o2); $subject->someBusinessLogic(); $subject->someBusinessLogic(); $subject->detach($o2); $subject->someBusinessLogic(); ``` </details> <br /> 输出 ``` Subject: Attached an observer. Subject: Attached an observer. Subject: I'm doing something important. Subject: My state has just changed to: 2 Subject: Notifying observers... ConcreteObserverA: Reacted to the event. ConcreteObserverB: Reacted to the event. Subject: I'm doing something important. Subject: My state has just changed to: 4 Subject: Notifying observers... ConcreteObserverB: Reacted to the event. Subject: Detached an observer. Subject: I'm doing something important. Subject: My state has just changed to: 1 Subject: Notifying observers... ConcreteObserverA: Reacted to the event. ``` ### 添加多种事件通知用户 <details> <summary>main.go</summary> ``` <?php class UserRepository implements SplSubject { /** * @var array The list of users. */ private $users = []; /** * @var array */ private $observers = []; public function __construct() { $this->observers["*"] = []; } // 检测事件是否存在,不存在则初始化数据库 private function initEventGroup(string $event = "*"): void { if (!isset($this->observers[$event])) { $this->observers[$event] = []; } } private function getEventObservers(string $event = "*"): array { $this->initEventGroup($event); $group = $this->observers[$event]; // 获取 "*" 的所有事件 $all = $this->observers["*"]; return array_merge($group, $all); } public function attach(SplObserver $observer, string $event = "*"): void { $this->initEventGroup($event); $this->observers[$event][] = $observer; } public function detach(SplObserver $observer, string $event = "*"): void { foreach ($this->getEventObservers($event) as $key => $s) { if ($s === $observer) { unset($this->observers[$event][$key]); } } } public function notify(string $event = "*", $data = null): void { foreach ($this->getEventObservers($event) as $observer) { $observer->update($this, $event, $data); } } public function initialize($filename): void { // ... $this->notify("users:init", $filename); } public function createUser(array $data): User { $user = new User(); $user->update($data); // 给新用户一个唯一值 $id = bin2hex(openssl_random_pseudo_bytes(16)); $user->update(["id" => $id]); $this->users[$id] = $user; // 并通知用户 $this->notify("users:created", $user); return $user; } public function updateUser(User $user, array $data): ?User { $id = $user->attributes["id"]; if (!isset($this->users[$id])) { return null; } $user = $this->users[$id]; $user->update($data); $this->notify("users:updated", $user); return $user; } public function deleteUser(User $user): void { $id = $user->attributes["id"]; if (!isset($this->users[$id])) { return; } unset($this->users[$id]); $this->notify("users:deleted", $user); } } /** * Let's keep the User class trivial since it's not the focus of our example. */ class User { public $attributes = []; public function update($data): void { $this->attributes = array_merge($this->attributes, $data); } } class Logger implements SplObserver { private $filename; public function __construct($filename) { $this->filename = $filename; if (file_exists($this->filename)) { unlink($this->filename); } } public function update(SplSubject $repository, string $event = null, $data = null): void { $entry = date("Y-m-d H:i:s") . ": '$event' with data '" . json_encode($data) . "'\n"; file_put_contents($this->filename, $entry, FILE_APPEND); echo "[日志]: 写入 '$event' 事件到文件.\n\n"; } } // 新员工培训通知 class OnboardingNotification implements SplObserver { private $adminEmail; public function __construct($adminEmail) { $this->adminEmail = $adminEmail; } public function update(SplSubject $repository, string $event=null, $data = null): void { // 发送email // mail($this->adminEmail, // "Onboarding required", // "We have a new user. Here's his info: " .json_encode($data)); echo "[通知] 新员工培训通知:通知已发邮件!\n"; } } /** * The client code. */ $repository = new UserRepository(); $repository->attach(new Logger(__DIR__ . "/log.txt"), "*"); // 只有在创建时人员时,才通知 $repository->attach(new OnboardingNotification("1@example.com"), "users:created"); $repository->initialize(__DIR__ . "/users.csv"); // ... $user = $repository->createUser([ "name" => "John Smith", "email" => "john99@example.com", ]); // ... $repository->updateUser($user,['age'=>10]); $repository->deleteUser($user); ``` </details> <br /> 输出 ``` [日志]: 写入 'users:init' 事件到文件. [通知] 新员工培训通知:通知已发邮件! [日志]: 写入 'users:created' 事件到文件. [日志]: 写入 'users:updated' 事件到文件. [日志]: 写入 'users:deleted' 事件到文件. ```