PHP中的Event Bus与观察者模式
在现代PHP Web应用开发中,经常需要灵活响应各种事件:注册后发送邮件、记录用户操作、数据变更时更新缓存等。观察者模式及其扩展——Event Bus(事件总线)非常适合这些场景。
观察者模式:基础
观察者模式是一种行为设计模式,它创建了一种订阅机制,允许一个对象关注并响应其他对象中发生的事件。主要组件包括:
- Subject(主体) — 生成事件的对象
- Observer(观察者) — 响应事件的对象
- Event(事件) — 关于已发生动作的信息
Event Bus:观察者模式的演进
Event Bus是一个集中式总线,管理应用程序中的所有事件。与经典观察者模式中订阅与主体紧密绑定不同,Event Bus提供:
- 发送方与接收方的松耦合
- 运行时动态添加/移除处理器的能力
- 从应用程序任何部分全局访问总线
- 简化的测试与调试
PHP中Event Bus的实现示例
让我们创建一个简单但功能完整的Event Bus实现,兼容PSR-14(事件分发器)。
<?php// 事件接口interface EventInterface{ public function getName(): string;}
// 基础事件class UserRegisteredEvent implements EventInterface{ public function __construct( private string $email, private string $username ) {}
public function getName(): string { return 'user.registered'; }
public function getEmail(): string { return $this->email; }
public function getUsername(): string { return $this->username; }}
// 处理器接口interface EventHandlerInterface{ public function handle(EventInterface $event): void;}
// Event Busclass EventBus{ private array $listeners = [];
public function addListener(string $eventName, EventHandlerInterface $handler): void { $this->listeners[$eventName][] = $handler; }
public function removeListener(string $eventName, EventHandlerInterface $handler): void { if (!isset($this->listeners[$eventName])) { return; }
$this->listeners[$eventName] = array_filter( $this->listeners[$eventName], fn($h) => $h !== $handler ); }
public function dispatch(EventInterface $event): void { $eventName = $event->getName();
if (!isset($this->listeners[$eventName])) { return; }
foreach ($this->listeners[$eventName] as $handler) { $handler->handle($event); } }}?>实际使用
现在创建处理器并演示总线的工作:
<?php// 发送邮件的处理器class SendWelcomeEmailHandler implements EventHandlerInterface{ public function handle(EventInterface $event): void { if (!$event instanceof UserRegisteredEvent) { return; }
echo "正在向 {$event->getEmail()} 发送欢迎邮件"; // mail($event->getEmail(), '欢迎!', '...'); }}
// 日志记录处理器class LogUserRegistrationHandler implements EventHandlerInterface{ public function handle(EventInterface $event): void { if (!$event instanceof UserRegisteredEvent) { return;