PHP观察者模式实现事件

wen PHP项目 2

本文目录导读:

PHP观察者模式实现事件

  1. 基础观察者模式实现
  2. 使用示例
  3. PHP内置的SplObserver实现
  4. 实际应用场景:订单系统
  5. 事件分发器实现
  6. 注意事项和最佳实践
  7. 与框架集成示例(Laravel风格)

我来详细讲解PHP中观察者模式的实现,包括基础实现和实际应用场景。

基础观察者模式实现

观察者接口

<?php
// 观察者接口
interface Observer {
    public function update(string $event, mixed $data = null): void;
}
// 主题接口(被观察者)
interface Subject {
    public function attach(Observer $observer): void;
    public function detach(Observer $observer): void;
    public function notify(string $event, mixed $data = null): void;
}

具体主题类

<?php
class EventManager implements Subject {
    private array $observers = [];
    private array $events = [];
    public function attach(Observer $observer): void {
        // 使用SplObjectStorage存储,避免重复添加
        if (!in_array($observer, $this->observers, true)) {
            $this->observers[] = $observer;
        }
    }
    public function detach(Observer $observer): void {
        $key = array_search($observer, $this->observers, true);
        if ($key !== false) {
            unset($this->observers[$key]);
            $this->observers = array_values($this->observers);
        }
    }
    public function notify(string $event, mixed $data = null): void {
        foreach ($this->observers as $observer) {
            $observer->update($event, $data);
        }
    }
    // 按事件分类通知
    public function notifyByEvent(string $event, mixed $data = null): void {
        foreach ($this->observers as $observer) {
            if ($observer->canHandle($event)) {
                $observer->update($event, $data);
            }
        }
    }
}

具体观察者

<?php
class EmailNotifier implements Observer {
    private string $email;
    public function __construct(string $email) {
        $this->email = $email;
    }
    public function update(string $event, mixed $data = null): void {
        echo "发送邮件到 {$this->email}:发生了事件 {$event}\n";
        if ($data) {
            echo "事件数据: " . json_encode($data) . "\n";
        }
    }
    public function canHandle(string $event): bool {
        return in_array($event, ['user.registered', 'password.reset']);
    }
}
class LogObserver implements Observer {
    private string $logFile;
    public function __construct(string $logFile = 'app.log') {
        $this->logFile = $logFile;
    }
    public function update(string $event, mixed $data = null): void {
        $logEntry = sprintf(
            "[%s] Event: %s, Data: %s\n",
            date('Y-m-d H:i:s'),
            $event,
            json_encode($data)
        );
        file_put_contents($this->logFile, $logEntry, FILE_APPEND);
    }
    public function canHandle(string $event): bool {
        return true; // 记录所有事件
    }
}
class MetricsCollector implements Observer {
    private array $metrics = [];
    public function update(string $event, mixed $data = null): void {
        if (!isset($this->metrics[$event])) {
            $this->metrics[$event] = 0;
        }
        $this->metrics[$event]++;
        echo "指标统计: {$event} 发生次数: {$this->metrics[$event]}\n";
    }
    public function canHandle(string $event): bool {
        return true;
    }
    public function getMetrics(): array {
        return $this->metrics;
    }
}

使用示例

<?php
// 使用示例
$eventManager = new EventManager();
// 创建观察者
$emailNotifier = new EmailNotifier('admin@example.com');
$logObserver = new LogObserver('/tmp/app.log');
$metrics = new MetricsCollector();
// 注册观察者
$eventManager->attach($emailNotifier);
$eventManager->attach($logObserver);
$eventManager->attach($metrics);
// 触发事件
$eventManager->notify('user.registered', [
    'user_id' => 1,
    'email' => 'user@example.com',
    'created_at' => date('Y-m-d H:i:s')
]);
$eventManager->notify('user.login', [
    'user_id' => 1,
    'login_time' => date('Y-m-d H:i:s')
]);
// 移除观察者
$eventManager->detach($emailNotifier);
$eventManager->notify('user.logout', ['user_id' => 1]);

PHP内置的SplObserver实现

<?php
// 使用PHP内置接口
class User implements SplSubject {
    private SplObjectStorage $observers;
    private array $userData;
    public function __construct() {
        $this->observers = new SplObjectStorage();
    }
    public function attach(SplObserver $observer): void {
        $this->observers->attach($observer);
    }
    public function detach(SplObserver $observer): void {
        $this->observers->detach($observer);
    }
    public function notify(): void {
        foreach ($this->observers as $observer) {
            $observer->update($this);
        }
    }
    public function setUserData(array $data): void {
        $this->userData = $data;
        $this->notify();
    }
    public function getUserData(): array {
        return $this->userData;
    }
}
class UserObserver implements SplObserver {
    private string $name;
    public function __construct(string $name) {
        $this->name = $name;
    }
    public function update(SplSubject $subject): void {
        if ($subject instanceof User) {
            echo "观察者 {$this->name} 收到更新:";
            echo json_encode($subject->getUserData()) . "\n";
        }
    }
}
// 使用SplObserver
$user = new User();
$observer1 = new UserObserver('观察者A');
$observer2 = new UserObserver('观察者B');
$user->attach($observer1);
$user->attach($observer2);
$user->setUserData(['name' => '张三', 'age' => 25]);

实际应用场景:订单系统

<?php
// 订单事件观察者模式
interface OrderObserver {
    public function onOrderCreated(Order $order): void;
    public function onOrderPaid(Order $order): void;
    public function onOrderCanceled(Order $order): void;
}
// 订单类
class Order {
    private array $observers = [];
    private array $orderData;
    public function __construct(array $orderData) {
        $this->orderData = $orderData;
    }
    public function attach(OrderObserver $observer): void {
        $this->observers[] = $observer;
    }
    public function detach(OrderObserver $observer): void {
        $key = array_search($observer, $this->observers, true);
        if ($key !== false) {
            unset($this->observers[$key]);
        }
    }
    public function create(): void {
        echo "订单已创建\n";
        $this->notify('onOrderCreated');
    }
    public function pay(): void {
        $this->orderData['status'] = 'paid';
        echo "订单已支付\n";
        $this->notify('onOrderPaid');
    }
    public function cancel(): void {
        $this->orderData['status'] = 'canceled';
        echo "订单已取消\n";
        $this->notify('onOrderCanceled');
    }
    private function notify(string $method): void {
        foreach ($this->observers as $observer) {
            $observer->$method($this);
        }
    }
    public function getOrderData(): array {
        return $this->orderData;
    }
}
// 实际业务观察者
class InventoryService implements OrderObserver {
    public function onOrderCreated(Order $order): void {
        echo "库存系统:锁定商品库存\n";
    }
    public function onOrderPaid(Order $order): void {
        echo "库存系统:扣减库存\n";
    }
    public function onOrderCanceled(Order $order): void {
        echo "库存系统:释放库存\n";
    }
}
class PaymentService implements OrderObserver {
    public function onOrderCreated(Order $order): void {
        // 不处理
    }
    public function onOrderPaid(Order $order): void {
        echo "支付系统:处理支付结果\n";
    }
    public function onOrderCanceled(Order $order): void {
        echo "支付系统:处理退款\n";
    }
}
class NotificationService implements OrderObserver {
    public function onOrderCreated(Order $order): void {
        echo "通知系统:发送订单创建通知\n";
    }
    public function onOrderPaid(Order $order): void {
        echo "通知系统:发送支付成功通知\n";
    }
    public function onOrderCanceled(Order $order): void {
        echo "通知系统:发送订单取消通知\n";
    }
}
// 使用订单系统
$order = new Order([
    'id' => 'ORD001',
    'product_name' => 'iPhone 15',
    'price' => 7999,
    'status' => 'pending'
]);
// 注册观察者
$order->attach(new InventoryService());
$order->attach(new PaymentService());
$order->attach(new NotificationService());
// 业务流程
$order->create();
$order->pay();
// $order->cancel();  // 取消流程

事件分发器实现

<?php
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(string $eventName, array $payload = []): void {
        if (!isset($this->listeners[$eventName])) {
            return;
        }
        foreach ($this->listeners[$eventName] as $priorityListeners) {
            foreach ($priorityListeners as $listener) {
                call_user_func_array($listener, [$payload, $eventName]);
            }
        }
    }
    // 移除监听器
    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 => $existingListener) {
                if ($existingListener === $listener) {
                    unset($this->listeners[$eventName][$priority][$key]);
                }
            }
        }
    }
}
// 使用事件分发器
$dispatcher = new EventDispatcher();
// 注册事件
$dispatcher->addListener('user.register', function($data) {
    echo "发送注册邮件: " . $data['email'] . "\n";
}, 10);
$dispatcher->addListener('user.register', function($data) {
    echo "记录注册日志\n";
}, 5);
$dispatcher->addListener('user.login', function($data) {
    echo "用户 {$data['username']} 登录成功\n";
}, 1);
// 触发事件
$dispatcher->dispatch('user.register', ['email' => 'test@example.com', 'username' => '张三']);
$dispatcher->dispatch('user.login', ['username' => '张三']);

注意事项和最佳实践

<?php
// 1. 使用事件类封装数据
final class OrderCreated {
    public function __construct(
        public readonly Order $order,
        public readonly array $metadata = []
    ) {}
}
// 2. 观察者注册管理
class EventManager {
    private static ?EventManager $instance = null;
    private array $observers = [];
    public static function getInstance(): EventManager {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    // 防止克隆
    private function __clone() {}
    public function register(string $event, callable $callback, int $priority = 0): void {
        $this->observers[$event][] = [
            'callback' => $callback,
            'priority' => $priority
        ];
        // 按优先级排序
        usort($this->observers[$event], function($a, $b) {
            return $b['priority'] <=> $a['priority'];
        });
    }
    public function trigger(string $event, array $data = []): void {
        if (!isset($this->observers[$event])) {
            return;
        }
        foreach ($this->observers[$event] as $observer) {
            call_user_func($observer['callback'], $data, $event);
        }
    }
}
// 使用单例模式
$eventManager = EventManager::getInstance();
$eventManager->register('product.low_stock', function($data) {
    echo "商品库存不足: " . $data['product_id'] . "\n";
    // 发送邮件通知
}, 100);
$eventManager->trigger('product.low_stock', ['product_id' => 5, 'current' => 2]);

与框架集成示例(Laravel风格)

<?php
// 事件类
class OrderShipped {
    public function __construct(
        public Order $order,
        public string $shippedAt
    ) {}
}
// 监听器
class UpdateInventory {
    public function handle(OrderShipped $event): void {
        // 更新库存逻辑
        echo "更新库存:" . $event->order->id . "\n";
    }
}
// 事件监听器注册(通常在EventServiceProvider中)
$eventListeners = [
    OrderShipped::class => [
        UpdateInventory::class,
        SendOrderNotification::class,
        RecordTracking::class,
    ],
];
// 简单的事件分发器实现
class EventServiceProvider {
    private array $listeners = [];
    public function register(array $listeners): void {
        foreach ($listeners as $event => $eventListeners) {
            foreach ($eventListeners as $listener) {
                $this->listeners[$event][] = new $listener();
            }
        }
    }
    public function dispatch(object $event): void {
        $eventClass = get_class($event);
        if (!isset($this->listeners[$eventClass])) {
            return;
        }
        foreach ($this->listeners[$eventClass] as $listener) {
            $listener->handle($event);
        }
    }
}
// 使用
$provider = new EventServiceProvider();
$provider->register($eventListeners);
$event = new OrderShipped(new Order(['id' => 1]), date('Y-m-d H:i:s'));
$provider->dispatch($event);

观察者模式的优势:

  1. 解耦:主题和观察者之间松耦合
  2. 扩展性:轻松添加新的观察者
  3. 一致性:当状态变化时自动通知所有依赖者
  4. 复用性:观察者可以被多个主题使用

在实际开发中,建议:

  • 使用事件类封装事件数据
  • 考虑事件优先级
  • 实现事件撤销机制(如果必要)
  • 合理的性能优化(异步处理等)
  • 严格遵守单一职责原则

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