PHP中的事件总线与观察者模式:从理论到实践
在现代PHP开发中,越来越需要创建低耦合、灵活且可扩展的系统。实现这一目标的两个关键工具是观察者模式及其更高级的抽象——事件总线。在本文中,我们将探讨如何在PHP中实现这两种方法,并说明何时选择哪种工具。
什么是观察者模式?
观察者模式是一种行为设计模式,它在对象之间定义了一种一对多的依赖关系。当一个对象(发布者)改变其状态时,所有依赖对象(订阅者)都会自动收到通知。
PHP中观察者模式的简单实现:
<?phpinterface Observer { public function update(string $event, $data): void;}
interface Observable { public function attach(Observer $observer): void; public function detach(Observer $observer): void; public function notify(string $event, $data = null): void;}
class UserManager implements Observable { private array $observers = [];
public function attach(Observer $observer): void { $this->observers[] = $observer; }
public function detach(Observer $observer): void { $this->observers = array_filter( $this->observers, fn($obs) => $obs !== $observer ); }
public function notify(string $event, $data = null): void { foreach ($this->observers as $observer) { $observer->update($event, $data); } }
public function registerUser(string $name): void { // 注册逻辑 echo "用户 $name 已注册。"; $this->notify('user.registered', ['name' => $name]); }}
class EmailNotifier implements Observer { public function update(string $event, $data): void { if ($event === 'user.registered') { echo "向 {$data['name']} 发送欢迎邮件。"; } }}
class Logger implements Observer { public function update(string $event, $data): void { echo "记录事件日志: $event"; }}
// 使用示例$userManager = new UserManager();$userManager->attach(new EmailNotifier());$userManager->attach(new Logger());
$userManager->registerUser('伊万');?>经典观察者模式的缺点
- 强耦合——订阅者必须了解发布者。
- 缺乏灵活性——难以管理大量不同类型的事件。
- 测试困难——每个发布者都包含一个观察者列表。
事件总线——观察者模式的演进
事件总线是事件发布者与其订阅者之间的集中式中介。每个发布者对象不再管理自己的观察者列表,而是所有订阅和通知都通过一个统一的总线进行。
PHP中事件总线的实现
<?phpclass EventBus { private array $listeners = [];
public function subscribe(string $event, callable $handler): void { $this->listeners[$event][] = $handler; }
public function unsubscribe(string $event, callable $handler): void { if (!isset($this->listeners[$event])) { return; } $this->listeners[$event] = array_filter( $this->listeners[$event], fn($h) => $h !== $handler ); }
public function dispatch(string $event, $payload = null): void { if (!isset($this->listeners[$event])) { return; } foreach ($this->listeners[$event] as $handler) { call_user_func