本文目录导读:

我来详细讲解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);
观察者模式的优势:
- 解耦:主题和观察者之间松耦合
- 扩展性:轻松添加新的观察者
- 一致性:当状态变化时自动通知所有依赖者
- 复用性:观察者可以被多个主题使用
在实际开发中,建议:
- 使用事件类封装事件数据
- 考虑事件优先级
- 实现事件撤销机制(如果必要)
- 合理的性能优化(异步处理等)
- 严格遵守单一职责原则