本文目录导读:

在PHP项目中实现用户自定义事件,主要有以下几种常见方式,我会从简单到复杂依次介绍。
使用观察者模式(最推荐)
这是最常用的实现方式,Event类配合Listener/Handler。
基础实现
<?php
// 事件类
class Event
{
protected $name;
protected $data;
protected $stopped = false;
public function __construct($name, $data = [])
{
$this->name = $name;
$this->data = $data;
}
public function getName()
{
return $this->name;
}
public function getData()
{
return $this->data;
}
public function stopPropagation()
{
$this->stopped = true;
}
public function isPropagationStopped()
{
return $this->stopped;
}
}
// 事件分发器
class EventDispatcher
{
protected $listeners = [];
// 注册监听器
public function addListener($eventName, $callback, $priority = 0)
{
$this->listeners[$eventName][] = [
'callback' => $callback,
'priority' => $priority
];
}
// 触发事件
public function dispatch($eventName, Event $event = null)
{
if ($event === null) {
$event = new Event($eventName);
}
if (!isset($this->listeners[$eventName])) {
return $event;
}
// 按优先级排序
$listeners = $this->listeners[$eventName];
usort($listeners, function($a, $b) {
return $b['priority'] - $a['priority'];
});
foreach ($listeners as $listener) {
if ($event->isPropagationStopped()) {
break;
}
call_user_func($listener['callback'], $event);
}
return $event;
}
// 移除监听器
public function removeListener($eventName, $callback)
{
if (!isset($this->listeners[$eventName])) {
return;
}
foreach ($this->listeners[$eventName] as $key => $listener) {
if ($listener['callback'] === $callback) {
unset($this->listeners[$eventName][$key]);
}
}
}
}
// 使用示例
class UserService
{
protected $dispatcher;
public function __construct(EventDispatcher $dispatcher)
{
$this->dispatcher = $dispatcher;
}
public function register($username, $email)
{
// 用户注册逻辑...
// 触发注册事件
$event = new Event('user.registered', [
'username' => $username,
'email' => $email,
'time' => time()
]);
$this->dispatcher->dispatch('user.registered', $event);
return true;
}
}
// 创建分发器
$dispatcher = new EventDispatcher();
// 注册监听器
$dispatcher->addListener('user.registered', function(Event $event) {
$data = $event->getData();
echo "发送欢迎邮件给: " . $data['email'] . "\n";
});
$dispatcher->addListener('user.registered', function(Event $event) {
$data = $event->getData();
echo "记录日志: 用户 {$data['username']} 注册成功\n";
}, 10); // 优先级高
// 使用
$userService = new UserService($dispatcher);
$userService->register('张三', 'zhangsan@example.com');
使用PHP内置的SPL(标准PHP库)
<?php
class UserEvent extends SplSubject
{
protected $observers = [];
protected $data = [];
public function attach(SplObserver $observer)
{
$this->observers[] = $observer;
}
public function detach(SplObserver $observer)
{
foreach ($this->observers as $key => $obs) {
if ($obs === $observer) {
unset($this->observers[$key]);
}
}
}
public function notify()
{
foreach ($this->observers as $observer) {
$observer->update($this);
}
}
public function setData($data)
{
$this->data = $data;
}
public function getData()
{
return $this->data;
}
}
class EmailObserver implements SplObserver
{
public function update(SplSubject $subject)
{
$data = $subject->getData();
echo "发送邮件到: " . $data['email'] . "\n";
}
}
class LogObserver implements SplObserver
{
public function update(SplSubject $subject)
{
$data = $subject->getData();
echo "日志: 用户 {$data['username']} 操作\n";
}
}
// 使用
$event = new UserEvent();
$event->attach(new EmailObserver());
$event->attach(new LogObserver());
$event->setData([
'username' => '张三',
'email' => 'zhangsan@example.com'
]);
$event->notify();
基于类注解的事件系统(高级)
<?php
#[Attribute]
class Event
{
public string $name;
public function __construct(string $name)
{
$this->name = $name;
}
}
class EventAnnotationParser
{
public static function parse(string $className)
{
$reflection = new ReflectionClass($className);
$events = [];
foreach ($reflection->getMethods() as $method) {
$attributes = $method->getAttributes(Event::class);
foreach ($attributes as $attribute) {
$event = $attribute->newInstance();
$events[$event->name] = [
'class' => $className,
'method' => $method->getName()
];
}
}
return $events;
}
}
// 使用示例
class UserEventHandler
{
#[Event('user.registered')]
public function handleUserRegistered($data)
{
echo "处理用户注册事件: " . json_encode($data) . "\n";
}
#[Event('user.deleted')]
public function handleUserDeleted($data)
{
echo "处理用户删除事件: " . json_encode($data) . "\n";
}
}
// 自动注册事件
$events = EventAnnotationParser::parse(UserEventHandler::class);
// 可以自动注册到事件分发器
使用现有库(推荐生产环境)
Symfony EventDispatcher
// composer require symfony/event-dispatcher
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\Event;
class UserRegisteredEvent extends Event
{
const NAME = 'user.registered';
protected $user;
public function __construct($user)
{
$this->user = $user;
}
public function getUser()
{
return $this->user;
}
}
$dispatcher = new EventDispatcher();
$dispatcher->addListener(UserRegisteredEvent::NAME, function(UserRegisteredEvent $event) {
$user = $event->getUser();
echo "用户 {$user['name']} 注册成功\n";
});
$event = new UserRegisteredEvent(['name' => '张三', 'email' => 'test@test.com']);
$dispatcher->dispatch($event, UserRegisteredEvent::NAME);
Laravel 事件(如果你使用Laravel框架)
// 1. 创建事件类
// php artisan make:event UserRegistered
class UserRegistered
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $user;
public function __construct($user)
{
$this->user = $user;
}
}
// 2. 创建监听器
// php artisan make:listener SendWelcomeEmail
class SendWelcomeEmail
{
public function handle(UserRegistered $event)
{
// 发送欢迎邮件
Mail::to($event->user->email)->send(new WelcomeMail($event->user));
}
}
// 3. 注册监听器 (EventServiceProvider.php)
protected $listen = [
UserRegistered::class => [
SendWelcomeEmail::class,
UpdateUserStats::class,
],
];
// 4. 触发事件
event(new UserRegistered($user));
最佳实践建议
命名规范
// 使用点号分隔的事件名 'user.registered' 'user.deleted' 'order.created' 'payment.completed'
事件基类
abstract class BaseEvent
{
protected $stopPropagation = false;
protected $data = [];
abstract public function getName(): string;
public function stopPropagation(): void
{
$this->stopPropagation = true;
}
public function isPropagationStopped(): bool
{
return $this->stopPropagation;
}
}
异步事件处理
// 对于耗时操作,考虑异步处理
$dispatcher->addListener('user.registered', function($event) {
// 发送到消息队列
Queue::push('SendEmailJob', ['user_id' => $event->getUserId()]);
}, -100); // 低优先级,异步处理
错误处理
$dispatcher->addListener('user.registered', function($event) {
try {
// 事件处理逻辑
} catch (\Exception $e) {
// 记录错误日志,但不影响主流程
Log::error('Event handler failed: ' . $e->getMessage());
}
});
- 小项目:使用观察者模式手动实现
- 中等项目:使用SPL或简单的事件分发器
- 大型项目:使用Symfony EventDispatcher或框架自带的事件系统
- 性能要求高:考虑事件队列和异步处理
选择哪种方式取决于你的项目规模、性能需求和团队技术栈,建议从简单的模式开始,随着需求增长逐步升级。