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