ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、视频、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# SplSubject # [SplSubject interface](https://www.php.net/manual/zh/class.splsubject.php#class.splsubject) > SplSubject接口与SplObserver一起用于实现Observer观察者设计模式 > 被观察者, 负责维护观察者并在变化发生是通知观察者 ## **方法:** ``` <pre class="calibre10">``` SplSubject <span class="token3">{</span> <span class="token">/* 方法 */</span> abstract public attach <span class="token3">(</span> SplObserver $observer <span class="token3">)</span> <span class="token3">:</span> void <span class="token">//附加SplObserver观察者</span> abstract public detach <span class="token3">(</span> SplObserver $observer <span class="token3">)</span> <span class="token3">:</span> void <span class="token">//分离SplObserver观察者</span> abstract public notify <span class="token3">(</span> void <span class="token3">)</span> <span class="token3">:</span> void <span class="token">//通知SplObserver观察者</span> <span class="token3">}</span> ``` ``` ## \*\*方法:\*\*例子: ``` <pre class="calibre10">``` <span class="token">//观察者类</span> class <span class="token4">Observer</span> implements <span class="token4">SplObserver</span><span class="token3">{</span> public <span class="token5">function</span> <span class="token4">update</span><span class="token3">(</span>SplSubject $subject<span class="token3">)</span><span class="token3">{</span> <span class="token">//发邮件、发通知、写日志等逻辑写在这里</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//被观察者, 负责监听需要触发事件的类 维护观察者并在变化发生是通知观察者</span> class <span class="token4">Subject</span> implements <span class="token4">SplSubject</span><span class="token3">{</span> <span class="token">//附加SplObserver观察者</span> public <span class="token5">function</span> attach <span class="token3">(</span> SplObserver $observer <span class="token3">)</span><span class="token3">{</span> <span class="token">//一般用对象存储的方式存储传过来的观察者类</span> <span class="token3">}</span> <span class="token">//分离SplObserver观察者</span> public <span class="token5">function</span> detach <span class="token3">(</span> SplObserver $observer <span class="token3">)</span><span class="token3">{</span> <span class="token3">}</span> <span class="token">//通知SplObserver观察者</span> public <span class="token5">function</span> notify <span class="token3">(</span><span class="token3">)</span><span class="token3">{</span> <span class="token">//一般遍历对象存储的方式来逐个通知观察者</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//实例化观察者类</span> $observer<span class="token1">=</span> <span class="token5">new</span> <span class="token4">Observer</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token">//被观察者类 监听</span> $Subject<span class="token1">=</span><span class="token5">new</span> <span class="token4">Subject</span><span class="token3">(</span><span class="token2">'需要监听的类对象'</span><span class="token3">)</span><span class="token3">;</span> <span class="token">//添加观察者</span> $Subject<span class="token1">-</span><span class="token1">></span><span class="token4">attach</span><span class="token3">(</span>$observer<span class="token3">)</span><span class="token3">;</span> <span class="token">//移除观察者</span> $Subject<span class="token1">-</span><span class="token1">></span><span class="token4">detach</span><span class="token3">(</span>$observer<span class="token3">)</span><span class="token3">;</span> <span class="token">//通知观察者</span> $Subject<span class="token1">-</span><span class="token1">></span><span class="token4">notify</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> ``` ``` ``` <pre class="calibre17">``` <span class="token">/** * * 观察者模式 Observer * */</span> <span class="token5">function</span> <span class="token4">output</span><span class="token3">(</span>$string<span class="token3">)</span> <span class="token3">{</span> echo $string <span class="token3">.</span> <span class="token2">"n"</span><span class="token3">;</span> <span class="token3">}</span> <span class="token">//订单数据对象简单模拟,这个是实际需要被观察的对象(Subject),但是我们将其独立,然后 </span> <span class="token">//通过构造方法传入到我们模式中的Subject中,这样使具体业务更加独立 </span> class <span class="token4">Order</span><span class="token3">{</span> <span class="token">//订单号 </span> private $id <span class="token1">=</span> <span class="token2">''</span><span class="token3">;</span> <span class="token">//用户ID </span> private $userId <span class="token1">=</span> <span class="token2">''</span><span class="token3">;</span> <span class="token">//用户名 </span> private $userName <span class="token1">=</span> <span class="token2">''</span><span class="token3">;</span> <span class="token">//价格 </span> private $price <span class="token1">=</span> <span class="token2">''</span><span class="token3">;</span> <span class="token">//下单时间 </span> private $orderTime <span class="token1">=</span> <span class="token2">''</span><span class="token3">;</span> <span class="token">//订单数据填充简单模拟,实际应用中可能会读取用户表单输入并处理 </span> public <span class="token5">function</span> <span class="token4">__set</span><span class="token3">(</span>$name<span class="token3">,</span> $value<span class="token3">)</span><span class="token3">{</span> <span class="token5">if</span> <span class="token3">(</span><span class="token4">isset</span><span class="token3">(</span>$this<span class="token1">-</span><span class="token1">></span>$name<span class="token3">)</span><span class="token3">)</span><span class="token3">{</span> $this<span class="token1">-</span><span class="token1">></span>$name <span class="token1">=</span> $value<span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//获取订单属性 </span> public <span class="token5">function</span> <span class="token4">__get</span><span class="token3">(</span>$name<span class="token3">)</span><span class="token3">{</span> <span class="token5">if</span> <span class="token3">(</span><span class="token4">isset</span><span class="token3">(</span>$this<span class="token1">-</span><span class="token1">></span>$name<span class="token3">)</span><span class="token3">)</span><span class="token3">{</span> <span class="token5">return</span> $this<span class="token1">-</span><span class="token1">></span>$name<span class="token3">;</span> <span class="token3">}</span> <span class="token5">return</span> <span class="token2">""</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//被观察者, 负责监听类、维护观察者并在变化发生是通知观察者 </span> class <span class="token4">OrderSubject</span> implements <span class="token4">SplSubject</span> <span class="token3">{</span> private $observers<span class="token3">;</span> private $order<span class="token3">;</span> public <span class="token5">function</span> <span class="token4">__construct</span><span class="token3">(</span>Order $order<span class="token3">)</span> <span class="token3">{</span> $this<span class="token1">-</span><span class="token1">></span>observers <span class="token1">=</span> <span class="token5">new</span> <span class="token4">SplObjectStorage</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $this<span class="token1">-</span><span class="token1">></span>order <span class="token1">=</span> $order<span class="token3">;</span> <span class="token3">}</span> <span class="token">//增加一个观察者 </span> public <span class="token5">function</span> <span class="token4">attach</span><span class="token3">(</span>SplObserver $observer<span class="token3">)</span> <span class="token3">{</span> $this<span class="token1">-</span><span class="token1">></span>observers<span class="token1">-</span><span class="token1">></span><span class="token4">attach</span><span class="token3">(</span>$observer<span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token">//移除一个观察者 </span> public <span class="token5">function</span> <span class="token4">detach</span><span class="token3">(</span>SplObserver $observer<span class="token3">)</span> <span class="token3">{</span> $this<span class="token1">-</span><span class="token1">></span>observers<span class="token1">-</span><span class="token1">></span><span class="token4">detach</span><span class="token3">(</span>$observer<span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token">//通知所有观察者 </span> public <span class="token5">function</span> <span class="token4">notify</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> foreach <span class="token3">(</span>$this<span class="token1">-</span><span class="token1">></span>observers as $observer<span class="token3">)</span> <span class="token3">{</span> $observer<span class="token1">-</span><span class="token1">></span><span class="token4">update</span><span class="token3">(</span>$this<span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//返回主体对象的具体实现,供观察者调用 </span> public <span class="token5">function</span> <span class="token4">getOrder</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> <span class="token5">return</span> $this<span class="token1">-</span><span class="token1">></span>order<span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//观察者(事件类) 记录业务数据日志 (ActionLogObserver),实际可能还要抽象一层以处理不同的Action(业务操作),这里省略 </span> class <span class="token4">ActionLogObserver</span> implements <span class="token4">SplObserver</span><span class="token3">{</span> public <span class="token5">function</span> <span class="token4">update</span><span class="token3">(</span>SplSubject $subject<span class="token3">)</span> <span class="token3">{</span> $order <span class="token1">=</span> $subject<span class="token1">-</span><span class="token1">></span><span class="token4">getOrder</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token">//实际应用可能会写到日志文件中,这里直接输出 </span> <span class="token4">output</span><span class="token3">(</span> <span class="token2">"[OrderId:{$order->id}] [UseId:{$order->userId}] [Price:{$order->price}]"</span> <span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//观察者(事件类) 给用户发送订单确认邮件 (UserMailObserver) </span> class <span class="token4">UserMailObserver</span> implements <span class="token4">SplObserver</span><span class="token3">{</span> public <span class="token5">function</span> <span class="token4">update</span><span class="token3">(</span>SplSubject $subject<span class="token3">)</span> <span class="token3">{</span> $order <span class="token1">=</span> $subject<span class="token1">-</span><span class="token1">></span><span class="token4">getOrder</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token">//实际应用会调用邮件发送服务如sendmail,这里直接输出 </span> <span class="token4">output</span><span class="token3">(</span> <span class="token2">"Dear {$order->userName}: Your order {$order->id} was confirmed!"</span> <span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//观察者(事件类) 给管理人员发订单处理通知邮件 (AdminMailObserver) </span> class <span class="token4">AdminMailObserver</span> implements <span class="token4">SplObserver</span><span class="token3">{</span> public <span class="token5">function</span> <span class="token4">update</span><span class="token3">(</span>SplSubject $subject<span class="token3">)</span> <span class="token3">{</span> $order <span class="token1">=</span> $subject<span class="token1">-</span><span class="token1">></span><span class="token4">getOrder</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token">//实际应用会调用邮件发送服务如sendmail,这里直接输出 </span> <span class="token4">output</span><span class="token3">(</span> <span class="token2">"Dear Manager: User {$order->userName}(ID:{$order->userId}) submitted a new order {$order->id}, please handle it ASAP!"</span> <span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//假设的DB类,便于测试,实际会存入真实数据库 </span> class <span class="token4">FakeDB</span><span class="token3">{</span> public <span class="token5">function</span> <span class="token4">save</span><span class="token3">(</span>$data<span class="token3">)</span><span class="token3">{</span> <span class="token5">return</span> <span class="token6">true</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> Client<span class="token3">:</span><span class="token3">:</span><span class="token4">test</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token">//客户端调用 注意 </span> class <span class="token4">Client</span> <span class="token3">{</span> public static <span class="token5">function</span> <span class="token4">test</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> <span class="token">//初始化一个订单数据 </span> $order <span class="token1">=</span> <span class="token5">new</span> <span class="token4">Order</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $order<span class="token1">-</span><span class="token1">></span>id <span class="token1">=</span> <span class="token6">1001</span><span class="token3">;</span> $order<span class="token1">-</span><span class="token1">></span>userId <span class="token1">=</span> <span class="token6">9527</span><span class="token3">;</span> $order<span class="token1">-</span><span class="token1">></span>userName <span class="token1">=</span> <span class="token2">"God"</span><span class="token3">;</span> $order<span class="token1">-</span><span class="token1">></span>price <span class="token1">=</span> <span class="token6">20.0</span><span class="token3">;</span> $order<span class="token1">-</span><span class="token1">></span>orderTime <span class="token1">=</span> <span class="token4">time</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token">//监听order类</span> $subject <span class="token1">=</span> <span class="token5">new</span> <span class="token4">OrderSubject</span><span class="token3">(</span>$order<span class="token3">)</span><span class="token3">;</span> <span class="token">//监听其他类</span> <span class="token">//$subject2 = new OrderSubject($else); </span> $actionLogObserver <span class="token1">=</span> <span class="token5">new</span> <span class="token4">ActionLogObserver</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $userMailObserver <span class="token1">=</span> <span class="token5">new</span> <span class="token4">UserMailObserver</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $adminMailObserver <span class="token1">=</span> <span class="token5">new</span> <span class="token4">AdminMailObserver</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token">//增加一个观察者 </span> $subject<span class="token1">-</span><span class="token1">></span><span class="token4">attach</span><span class="token3">(</span>$actionLogObserver<span class="token3">)</span><span class="token3">;</span> $subject<span class="token1">-</span><span class="token1">></span><span class="token4">attach</span><span class="token3">(</span>$userMailObserver<span class="token3">)</span><span class="token3">;</span> $subject<span class="token1">-</span><span class="token1">></span><span class="token4">attach</span><span class="token3">(</span>$adminMailObserver<span class="token3">)</span><span class="token3">;</span> <span class="token">//向数据库保存订单 </span> $db <span class="token1">=</span> <span class="token5">new</span> <span class="token4">FakeDB</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $result <span class="token1">=</span> $db<span class="token1">-</span><span class="token1">></span><span class="token4">save</span><span class="token3">(</span>$order<span class="token3">)</span><span class="token3">;</span> <span class="token5">if</span> <span class="token3">(</span>$result<span class="token3">)</span><span class="token3">{</span> <span class="token">//保存订单成功通知观察者 </span> $subject<span class="token1">-</span><span class="token1">></span><span class="token4">notify</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token3">}</span> ``` ```