PHP 事件调度器原理

wen PHP项目 4

本文目录导读:

PHP 事件调度器原理

  1. 核心概念
  2. 基础实现原理
  3. 高级特性实现
  4. 实用事件调度器实现
  5. 实际应用示例
  6. 性能优化技巧
  7. 最佳实践建议

我将详细解释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;
    }
}
?>

最佳实践建议

  1. 使用接口而非具体类:定义统一的Event接口
  2. 惰性加载:对于大型事件系统,考虑按需加载监听器
  3. 缓存优化:缓存排序结果,避免重复计算
  4. 错误处理:监听器异常不应影响其他监听器执行
  5. 可测试性:设计为可注入mock的组件

PHP事件调度器的核心价值在于解耦系统和扩展性,通过事件驱动架构让系统更加灵活、可维护。

抱歉,评论功能暂时关闭!