PHP事件驱动架构怎么搭

wen PHP项目 2

本文目录导读:

PHP事件驱动架构怎么搭

  1. 核心概念
  2. 基础实现方案
  3. 完整架构设计
  4. 集成消息队列
  5. 异常处理和监控
  6. 最佳实践
  7. 测试策略
  8. 性能优化

我来详细讲解PHP事件驱动架构的搭建方法,从基础到实践逐步展开。

核心概念

事件驱动架构由三个核心组件组成:

  • 事件(Event):系统中发生的事实
  • 事件处理器(Handler):响应事件的逻辑
  • 事件调度器(Dispatcher):管理事件的发布和订阅

基础实现方案

1 使用现成库(推荐)

Symfony EventDispatcher(最流行):

composer require symfony/event-dispatcher

Laminas EventManager

composer require laminas/laminas-eventmanager

2 手写轻量级实现

<?php
namespace App\Event;
interface EventInterface
{
    public function getName(): string;
}
class OrderCreated implements EventInterface
{
    private string $orderId;
    public function __construct(string $orderId)
    {
        $this->orderId = $orderId;
    }
    public function getName(): string
    {
        return 'order.created';
    }
    public function getOrderId(): string
    {
        return $this->orderId;
    }
}
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 (empty($this->listeners[$eventName])) {
            return;
        }
        foreach ($this->listeners[$eventName] as $priority => $listeners) {
            foreach ($listeners as $listener) {
                call_user_func($listener, $event);
            }
        }
    }
}

完整架构设计

1 目录结构

src/
├── Event/
│   ├── EventInterface.php
│   ├── OrderCreated.php
│   ├── OrderShipped.php
│   └── UserRegistered.php
├── Listener/
│   ├── EmailNotifier.php
│   ├── InventoryUpdater.php
│   └── AnalyticsTracker.php
├── Dispatcher/
│   ├── EventDispatcher.php
│   └── EventSubscriberInterface.php
└── Middleware/
    ├── LoggingMiddleware.php
    └── AuthorizationMiddleware.php

2 高级事件调度器

<?php
namespace App\Dispatcher;
class EventDispatcher
{
    private array $listeners = [];
    private array $subscribers = [];
    private array $middlewares = [];
    public function __construct(array $middlewares = [])
    {
        $this->middlewares = $middlewares;
    }
    public function addListener(string $eventName, callable $listener, int $priority = 0): self
    {
        $this->listeners[$eventName][$priority][] = $listener;
        ksort($this->listeners[$eventName]);
        return $this;
    }
    public function addSubscriber(EventSubscriberInterface $subscriber): self
    {
        $this->subscribers[] = $subscriber;
        foreach ($subscriber->getSubscribedEvents() as $eventName => $method) {
            $priority = 0;
            if (is_array($method)) {
                [$method, $priority] = $method;
            }
            $this->addListener($eventName, [$subscriber, $method], $priority);
        }
        return $this;
    }
    public function dispatch(string $eventName, array $payload = []): void
    {
        $event = $this->createEvent($eventName, $payload);
        // 应用中间件
        $handler = function ($event) {
            $this->callListeners($event);
        };
        foreach (array_reverse($this->middlewares) as $middleware) {
            $handler = $middleware($handler);
        }
        $handler($event);
    }
    private function createEvent(string $eventName, array $payload): object
    {
        // 动态创建事件对象
        $className = "App\\Event\\" . ucfirst($eventName);
        return new $className(...$payload);
    }
    private function callListeners(object $event): void
    {
        $eventClass = get_class($event);
        $eventName = $this->getEventName($eventClass);
        if (empty($this->listeners[$eventName])) {
            return;
        }
        foreach ($this->listeners[$eventName] as $priority => $listeners) {
            foreach ($listeners as $listener) {
                $result = call_user_func($listener, $event);
                if ($result === false) {
                    break 2; // 停止传播
                }
            }
        }
    }
    private function getEventName(string $eventClass): string
    {
        $parts = explode('\\', $eventClass);
        return strtolower(end($parts));
    }
}
interface EventSubscriberInterface
{
    public static function getSubscribedEvents(): array;
}

3 具体事件和监听器

<?php
// 具体的订阅器
class OrderSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [
            'order.created' => ['onOrderCreated', 10],
            'order.shipped' => ['onOrderShipped', 5],
            'order.cancelled' => 'onOrderCancelled',
        ];
    }
    public function onOrderCreated(OrderCreated $event): void
    {
        // 发送确认邮件
        Mailer::sendOrderConfirmation($event->getOrderId());
        // 更新库存
        InventoryService::update($event->getOrderId());
        // 触发数据分析
        Analytics::track('order_created', ['order_id' => $event->getOrderId()]);
    }
    public function onOrderShipped(OrderShipped $event): void
    {
        // 更新物流状态
        ShippingService::updateStatus($event->getOrderId());
    }
    public function onOrderCancelled(OrderCancelled $event): void
    {
        // 退款处理
        PaymentService::refund($event->getOrderId());
    }
}

集成消息队列

<?php
// EventBus - 支持同步和异步事件
class EventBus
{
    private EventDispatcher $dispatcher;
    private ?QueueService $queue;
    private bool $syncMode = true;
    public function __construct(EventDispatcher $dispatcher, ?QueueService $queue = null)
    {
        $this->dispatcher = $dispatcher;
        $this->queue = $queue;
    }
    public function publish(EventInterface $event): void
    {
        if ($this->syncMode || !$this->queue) {
            // 同步处理
            $this->dispatcher->dispatch($event);
        } else {
            // 异步处理,存入消息队列
            $this->queue->push(json_encode([
                'event_class' => get_class($event),
                'data' => $event->serialize(),
            ]));
        }
    }
    // 消费队列
    public function consume(): void
    {
        while ($message = $this->queue->pop()) {
            $decoded = json_decode($message, true);
            $eventClass = $decoded['event_class'];
            $event = new $eventClass(...$decoded['data']);
            $this->dispatcher->dispatch($event);
        }
    }
}

异常处理和监控

<?php
namespace App\Middleware;
class ErrorHandlerMiddleware
{
    private LoggerInterface $logger;
    public function __invoke(callable $next): callable
    {
        return function ($event) use ($next) {
            try {
                return $next($event);
            } catch (\Throwable $e) {
                $this->logger->error('Event processing failed', [
                    'event' => get_class($event),
                    'error' => $e->getMessage(),
                    'trace' => $e->getTraceAsString(),
                ]);
                // TODO: 错误处理策略
                throw new EventProcessingException(
                    'Failed to process event: ' . get_class($event),
                    0,
                    $e
                );
            }
        };
    }
}
class MetricsMiddleware
{
    private StatsCollector $stats;
    public function __invoke(callable $next): callable
    {
        return function ($event) use ($next) {
            $startTime = microtime(true);
            // 执行后续处理器
            $result = $next($event);
            // 记录指标
            $this->stats->timing(
                'event.' . get_class($event),
                microtime(true) - $startTime
            );
            return $result;
        };
    }
}

最佳实践

1 事件命名规范

  • 使用过去时态表示已完成的行为:OrderCreated, UserRegistered
  • 使用点分格式order.created, payment.completed
  • 保持一致性:resource.action

2 匿名函数替代方案

// 使用invokable类
class SendWelcomeEmail
{
    public function __invoke(UserRegistered $event): void
    {
        // 发送欢迎邮件
    }
}
// 注册
$dispatcher->addListener('user.registered', new SendWelcomeEmail());

3 配置管理

// config/events.php
return [
    'listeners' => [
        'order.created' => [
            ['App\Listeners\SendOrderMail', 'handle'],
            ['App\Listeners\UpdateInventory', 'handle'],
        ],
        'user.registered' => [
            ['App\Listeners\SendWelcomeMail', 'handle'],
            ['App\Listeners\CreateDefaultFiles', 'handle'],
        ],
    ],
    'subscribers' => [
        App\Subscribers\OrderSubscriber::class,
        App\Subscribers\UserSubscriber::class,
    ],
    'async_events' => [
        'order.created' => true,
        'order.shipped' => true,
    ],
];

测试策略

<?php
class EventDispatcherTest extends TestCase
{
    public function testEventDispatch(): void
    {
        $dispatcher = new EventDispatcher();
        $invoked = false;
        $dispatcher->addListener('test.event', function () use (&$invoked) {
            $invoked = true;
        });
        $dispatcher->dispatch('test.event');
        $this->assertTrue($invoked);
    }
    public function testListenerPriority(): void
    {
        $dispatcher = new EventDispatcher();
        $executionOrder = [];
        $dispatcher->addListener('test.event', function () use (&$executionOrder) {
            $executionOrder[] = 'low';
        }, 0);
        $dispatcher->addListener('test.event', function () use (&$executionOrder) {
            $executionOrder[] = 'high';
        }, 100);
        $dispatcher->dispatch('test.event');
        $this->assertEquals(['high', 'low'], $executionOrder);
    }
}

性能优化

  1. 事件缓存:缓存已注册的监听器列表
  2. 异步处理:将非关键事件放入消息队列
  3. 事件索引:使用类似事件总线的结构快速定位处理器
  4. 惰性加载:延迟加载不常用的事件处理器

搭建PHP事件驱动架构的要点:

  • 选择合适的实现方案(Symfony/自定义)
  • 设计良好的事件命名和结构
  • 合理划分同步/异步处理
  • 实现完善的错误处理和监控
  • 遵循SOLID原则,保持组件解耦

这样的架构能够让你的应用更灵活、可扩展,同时保持代码清晰。

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