本文目录导读:

我将详细解释PHP事件调度器的原理,从基础概念到实际实现。
核心概念
事件调度器的三个核心组件:
- 事件(Event):发生的动作或状态变化
- 监听器(Listener):对事件做出响应的回调函数
- 调度器(Dispatcher):维护事件和监听器的映射关系,并触发事件
基础实现原理
简单的观察者模式实现:
<?php
interface EventInterface
{
public function getName(): string;
}
class OrderCreatedEvent implements EventInterface
{
public function getName(): string
{
return 'order.created';
}
public function getOrder()
{
return $this->order;
}
}
class EventDispatcher
{
private array $listeners = [];
// 注册监听器
public function addListener(string $eventName, callable $listener, int $priority = 0): void
{
$this->listeners[$eventName][$priority][] = $listener;
// 按优先级排序
ksort($this->listeners[$eventName]);
}
// 触发事件
public function dispatch(EventInterface $event): void
{
$eventName = $event->getName();
if (!isset($this->listeners[$eventName])) {
return;
}
// 按优先级顺序执行监听器
foreach ($this->listeners[$eventName] as $priority => $listeners) {
foreach ($listeners as $listener) {
// 调用回调函数
call_user_func($listener, $event);
}
}
}
// 移除监听器
public function removeListener(string $eventName, callable $listener): void
{
// 实现逻辑
}
}
// 使用示例
$dispatcher = new EventDispatcher();
$dispatcher->addListener('order.created', function(OrderCreatedEvent $event) {
$order = $event->getOrder();
// 发送邮件通知
echo "已发送订单通知邮件\n";
});
$dispatcher->addListener('order.created', function(OrderCreatedEvent $event) {
// 更新库存
echo "已更新库存\n";
}, 10); // 优先级更高
$dispatcher->dispatch(new OrderCreatedEvent($order));
?>
高级特性实现
1 事件传播控制
<?php
class EventDispatcher
{
private array $listeners = [];
public function dispatch(EventInterface $event): EventInterface
{
$eventName = $event->getName();
if (isset($this->listeners[$eventName])) {
foreach ($this->listeners[$eventName] as $listener) {
// 检测事件是否被停止传播
if ($event->isPropagationStopped()) {
break;
}
$listener($event);
}
}
return $event;
}
}
// 支持停止传播的事件
interface StoppableEventInterface extends EventInterface
{
public function stopPropagation(): void;
public function isPropagationStopped(): bool;
}
class OrderCreatedEvent implements StoppableEventInterface
{
private bool $propagationStopped = false;
public function stopPropagation(): void
{
$this->propagationStopped = true;
}
public function isPropagationStopped(): bool
{
return $this->propagationStopped;
}
}
?>
2 支持通配符监听
<?php
class EventDispatcher
{
public function dispatch(EventInterface $event): void
{
$eventName = $event->getName();
// 先匹配精确的事件名
$this->runListeners($eventName, $event);
// 再匹配通配符
foreach ($this->listeners as $pattern => $listeners) {
if ($this->matchPattern($pattern, $eventName)) {
$this->runListeners($pattern, $event);
}
}
}
private function matchPattern(string $pattern, string $eventName): bool
{
$pattern = preg_quote($pattern, '/');
$pattern = str_replace('\*', '.*', $pattern);
return (bool) preg_match("/^$pattern$/", $eventName);
}
}
// 示例:注册通配符监听器
$dispatcher->addListener('order.*', function(EventInterface $event) {
// 监听所有订单相关事件
});
?>
实用事件调度器实现
<?php
namespace App\EventDispatcher;
class EventDispatcher
{
private array $listeners = [];
private array $eventInstances = [];
private array $sortedEvents = [];
/**
* 注册事件监听器
*/
public function addListener(
string $eventName,
callable $listener,
int $priority = 0
): void {
$this->listeners[$eventName][$priority][] = $listener;
unset($this->sortedEvents[$eventName]); // 清除缓存
}
/**
* 触发事件
*/
public function dispatch(string $eventName, object $event = null): object
{
$event = $event ?? new Event($eventName);
// 调用所有监听器
foreach ($this->getListeners($eventName) as $listener) {
if ($event instanceof StoppableEventInterface && $event->isPropagationStopped()) {
break;
}
$listener($event, $eventName, $this);
}
return $event;
}
/**
* 获取按优先级排序的监听器
*/
private function getListeners(string $eventName): array
{
// 检查缓存
if (isset($this->sortedEvents[$eventName])) {
return $this->sortedEvents[$eventName];
}
$matchedListeners = [];
// 查找所有匹配的监听器
foreach ($this->listeners as $listenerEventName => $prioritizedListeners) {
if ($this->matchEventName($listenerEventName, $eventName)) {
foreach ($prioritizedListeners as $priority => $listeners) {
foreach ($listeners as $listener) {
$matchedListeners[$priority][] = $listener;
}
}
}
}
// 按优先级排序
ksort($matchedListeners);
// 扁平化数组
$sortedListeners = [];
foreach ($matchedListeners as $listeners) {
array_push($sortedListeners, ...$listeners);
}
// 缓存结果
$this->sortedEvents[$eventName] = $sortedListeners;
return $sortedListeners;
}
/**
* 移除监听器
*/
public function removeListener(string $eventName, callable $listener): void
{
if (!isset($this->listeners[$eventName])) {
return;
}
foreach ($this->listeners[$eventName] as $priority => $listeners) {
foreach ($listeners as $key => $currentListener) {
if ($currentListener === $listener) {
unset($this->listeners[$eventName][$priority][$key]);
}
}
}
unset($this->sortedEvents[$eventName]);
}
/**
* 事件名称匹配(支持通配符)
*/
private function matchEventName(string $listenerEventName, string $eventName): bool
{
if ($listenerEventName === $eventName) {
return true;
}
if (strpos($listenerEventName, '*') !== false) {
$pattern = str_replace('*', '.*', $listenerEventName);
return (bool) preg_match("/^$pattern$/", $eventName);
}
return false;
}
}
// 基础事件类
class Event
{
protected array $data = [];
public function __construct(string $name = null, array $data = [])
{
$this->data = $data;
}
public function set(string $key, $value): void
{
$this->data[$key] = $value;
}
public function get(string $key, $default = null)
{
return $this->data[$key] ?? $default;
}
}
?>
实际应用示例
<?php
// 订单系统中的应用
class OrderService
{
private EventDispatcher $dispatcher;
public function __construct(EventDispatcher $dispatcher)
{
$this->dispatcher = $dispatcher;
}
public function createOrder($userId, $items): Order
{
// 创建订单
$order = new Order($userId, $items);
// 触发订单创建事件
$this->dispatcher->dispatch('order.created', new Event(null, [
'order' => $order,
'userId' => $userId
]));
return $order;
}
}
// 配置监听器
$dispatcher = new EventDispatcher();
// 发送通知
$dispatcher->addListener('order.created', function(Event $event) {
$order = $event->get('order');
echo "发送订单通知: #{$order->getId()}\n";
}, 10);
// 记录日志
$dispatcher->addListener('order.created', function(Event $event) {
echo "记录订单日志\n";
}, 5);
// 更新库存
$dispatcher->addListener('order.*', function(Event $event) {
echo "处理订单相关事件\n";
});
// 使用
$orderService = new OrderService($dispatcher);
$order = $orderService->createOrder(1, ['product1', 'product2']);
?>
性能优化技巧
<?php
class EventDispatcherOptimized
{
private array $listeners = [];
private array $sortedListeners = [];
private array $wildcardListeners = [];
public function addListener(string $eventName, callable $listener, int $priority = 0): void
{
if (strpos($eventName, '*') !== false) {
$this->wildcardListeners[$eventName][] = ['priority' => $priority, 'listener' => $listener];
} else {
$this->listeners[$eventName][$priority][] = $listener;
}
// 清除相关的缓存
unset($this->sortedListeners[$eventName]);
}
public function dispatch(string $eventName, object $event = null): object
{
$event = $event ?? new Event($eventName);
// 获取并执行监听器
foreach ($this->getListeners($eventName) as $listener) {
$listener($event, $eventName);
}
return $event;
}
private function getListeners(string $eventName): array
{
// 检查缓存
if (isset($this->sortedListeners[$eventName])) {
return $this->sortedListeners[$eventName];
}
$listeners = [];
// 合并精确匹配的监听器
if (isset($this->listeners[$eventName])) {
$listeners = $this->listeners[$eventName];
}
// 合并通配符匹配的监听器
foreach ($this->wildcardListeners as $pattern => $wildcardListeners) {
if ($this->matchWildcard($pattern, $eventName)) {
foreach ($wildcardListeners as $wl) {
$listeners[$wl['priority']][] = $wl['listener'];
}
}
}
// 排序并扁平化
ksort($listeners);
$flattened = [];
foreach ($listeners as $priorityListeners) {
array_push($flattened, ...$priorityListeners);
}
$this->sortedListeners[$eventName] = $flattened;
return $flattened;
}
}
?>
最佳实践建议
- 使用接口而非具体类:定义统一的Event接口
- 惰性加载:对于大型事件系统,考虑按需加载监听器
- 缓存优化:缓存排序结果,避免重复计算
- 错误处理:监听器异常不应影响其他监听器执行
- 可测试性:设计为可注入mock的组件
PHP事件调度器的核心价值在于解耦系统和扩展性,通过事件驱动架构让系统更加灵活、可维护。