本文目录导读:

设计一个PHP事件系统,核心是解耦代码逻辑——让“发生什么”和“做什么”分离,下面从设计原则到具体实现,给出一个完整的方案。
核心概念
- 事件(Event):描述发生的事情,携带数据
- 监听器(Listener):对事件做出反应,执行逻辑
- 调度器(Dispatcher):触发事件,通知所有监听器
- 订阅器(Subscriber):批量注册多个监听器
基础架构设计
事件接口定义
<?php
namespace App\Event;
interface EventInterface
{
/**
* 获取事件名称(可选,可用于自动映射)
*/
public function getName(): string;
/**
* 停止事件传播
*/
public function isPropagationStopped(): bool;
/**
* 停止传播
*/
public function stopPropagation(): void;
}
基础事件类
<?php
namespace App\Event;
use App\Event\EventInterface;
class Event implements EventInterface
{
protected string $name;
protected bool $propagationStopped = false;
protected array $data = [];
public function __construct(string $name = '', array $data = [])
{
$this->name = $name ?: static::class;
$this->data = $data;
}
public function getName(): string
{
return $this->name;
}
public function getData(): array
{
return $this->data;
}
public function get(string $key, mixed $default = null): mixed
{
return $this->data[$key] ?? $default;
}
public function set(string $key, mixed $value): self
{
$this->data[$key] = $value;
return $this;
}
public function isPropagationStopped(): bool
{
return $this->propagationStopped;
}
public function stopPropagation(): void
{
$this->propagationStopped = true;
}
}
事件调度器
<?php
namespace App\Event;
use App\Event\EventInterface;
use InvalidArgumentException;
class EventDispatcher
{
/**
* 事件 => 监听器列表
* @var array<string, array<int, callable|array>>
*/
private array $listeners = [];
/**
* 注册监听器
*/
public function addListener(string $eventName, callable $listener, int $priority = 0): void
{
if (!isset($this->listeners[$eventName])) {
$this->listeners[$eventName] = [];
}
// 使用优先级排序
$this->listeners[$eventName][$priority][] = $listener;
krsort($this->listeners[$eventName]); // 高优先级在前
}
/**
* 移除监听器
*/
public function removeListener(string $eventName, callable $listener): bool
{
if (!isset($this->listeners[$eventName])) {
return false;
}
foreach ($this->listeners[$eventName] as $priority => $listeners) {
foreach ($listeners as $key => $registeredListener) {
if ($registeredListener === $listener) {
unset($this->listeners[$eventName][$priority][$key]);
return true;
}
}
}
return false;
}
/**
* 触发事件
*/
public function dispatch(EventInterface $event): EventInterface
{
$eventName = $event->getName();
if (!isset($this->listeners[$eventName])) {
return $event;
}
foreach ($this->listeners[$eventName] as $priority => $listeners) {
if ($event->isPropagationStopped()) {
break;
}
foreach ($listeners as $listener) {
if ($event->isPropagationStopped()) {
break;
}
$result = call_user_func($listener, $event);
// 如果监听器返回 false,停止传播
if ($result === false) {
$event->stopPropagation();
}
}
}
return $event;
}
/**
* 获取所有监听器
*/
public function getListeners(string $eventName = null): array
{
if ($eventName !== null) {
return $this->flatten($this->listeners[$eventName] ?? []);
}
$all = [];
foreach ($this->listeners as $name => $listeners) {
$all[$name] = $this->flatten($listeners);
}
return $all;
}
/**
* 扁平化优先级数组
*/
private function flatten(array $listeners): array
{
$result = [];
foreach ($listeners as $priority => $items) {
foreach ($items as $item) {
$result[] = $item;
}
}
return $result;
}
}
订阅器支持
<?php
namespace App\Event;
interface EventSubscriberInterface
{
/**
* 返回订阅的事件列表
*
* @return array<string, array|string>
* 例:['user.created' => 'onUserCreated', 'user.updated' => ['onUserUpdated', 10]]
*/
public static function getSubscribedEvents(): array;
}
在调度器中添加订阅器注册方法:
public function addSubscriber(EventSubscriberInterface $subscriber): void
{
foreach ($subscriber::getSubscribedEvents() as $eventName => $params) {
if (is_string($params)) {
$this->addListener($eventName, [$subscriber, $params]);
} elseif (is_array($params)) {
foreach ($params as $listener) {
if (is_string($listener)) {
$this->addListener($eventName, [$subscriber, $listener]);
} elseif (is_array($listener) && count($listener) === 2) {
$this->addListener($eventName, [$subscriber, $listener[0]], $listener[1]);
}
}
}
}
}
具体事件示例
<?php
namespace App\Event\Domain;
use App\Event\Event;
class UserCreatedEvent extends Event
{
public const NAME = 'user.created';
public function __construct(
private readonly int $userId,
private readonly array $userData = []
) {
parent::__construct(self::NAME);
}
public function getUserId(): int
{
return $this->userId;
}
public function getUserData(): array
{
return $this->userData;
}
}
事件总线(封装调度器)
<?php
namespace App\Event;
class EventBus
{
private static ?EventBus $instance = null;
private EventDispatcher $dispatcher;
private function __construct()
{
$this->dispatcher = new EventDispatcher();
}
public static function getInstance(): EventBus
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
public function emit(EventInterface $event): void
{
$this->dispatcher->dispatch($event);
}
public function on(string $eventName, callable $listener, int $priority = 0): void
{
$this->dispatcher->addListener($eventName, $listener, $priority);
}
public function subscribe(EventSubscriberInterface $subscriber): void
{
$this->dispatcher->addSubscriber($subscriber);
}
}
使用示例
<?php
// 注册监听器
$dispatcher = new EventDispatcher();
// 方法一:闭包监听器
$dispatcher->addListener('user.created', function (UserCreatedEvent $event) {
// 发送欢迎邮件
Mailer::send($event->getUserData()['email'], '欢迎注册');
}, 10); // 优先级10
// 方法二:类方法监听器
class SendSmsListener
{
public function onUserCreated(UserCreatedEvent $event): void
{
// 发送短信通知
}
}
$dispatcher->addListener('user.created', [new SendSmsListener(), 'onUserCreated']);
// 触发事件
$event = new UserCreatedEvent(123, ['email' => 'user@example.com']);
$dispatcher->dispatch($event);
高级特性设计
异步事件
<?php
trait AsyncEventTrait
{
private bool $async = false;
private int $delaySeconds = 0;
public function setAsync(bool $async = true): self
{
$this->async = $async;
return $this;
}
public function isAsync(): bool
{
return $this->async;
}
public function setDelay(int $seconds): self
{
$this->delaySeconds = $seconds;
return $this;
}
}
事件追踪
<?php
class TraceEventDispatcher extends EventDispatcher
{
private array $history = [];
public function dispatch(EventInterface $event): EventInterface
{
$this->history[] = [
'event' => $event->getName(),
'time' => microtime(true),
'memory' => memory_get_usage(),
];
return parent::dispatch($event);
}
public function getHistory(): array
{
return $this->history;
}
}
容器集成
<?php
// 与依赖注入容器结合
class ContainerAwareDispatcher extends EventDispatcher
{
public function __construct(
private readonly ContainerInterface $container
) {}
public function dispatchNamed(string $eventName, array $params = []): EventInterface
{
$event = new Event($eventName, $params);
return $this->dispatch($event);
}
// 从容器解析监听器
public function registerFromContainer(string $eventName, string $serviceId, string $method = '__invoke'): void
{
$this->addListener($eventName, function ($event) use ($serviceId, $method) {
$service = $this->container->get($serviceId);
return $service->{$method}($event);
});
}
}
设计要点总结
规范建议
- 命名规范:
{实体}.{动作},如user.created、order.paid - 参数传递:通过事件对象传递数据,不要直接传数组
- 返回值约定:监听器返回
false或调用stopPropagation()停止传播 - 异常处理:监听器异常不影响其他监听器执行
性能考虑
// 使用索引优化
private array $listenerIndex = [];
// 事件名称哈希索引
public function addListener(string $eventName, callable $listener, int $priority = 0): void
{
$hash = md5($eventName);
// ... 使用哈希索引
}
测试建议
- 单元测试:测试调度器逻辑
- 集成测试:测试具体业务事件
- 性能测试:大量事件触发下的性能表现
这个设计涵盖了事件系统的主要功能需求,可以根据项目实际情况选择合适的部分使用。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播