Symfony事件系统基于对象和契约设计,通过定义事件类、分发事件对象、编写监听器三步实现解耦,避免字符串硬编码,支持类型安全与自动注册。

Symfony事件系统不是靠“注册字符串事件名”硬编码实现的,而是基于对象和契约的现代设计。核心在于:定义事件对象、分发它、监听它——三步清晰解耦,不依赖全局事件名字符串。
创建自定义事件类
事件本身是一个普通 PHP 类,继承 Symfony\Contracts\EventDispatcher\Event(推荐),或直接作为空标记类(如测试场景)。关键点:
- 用 final 修饰,避免意外继承
- 构造函数接收业务数据(如 User、Order、Project 实例)
- 提供类型安全的 getter 方法,不暴露内部状态
- 可选定义常量 NAME,便于调试或旧式注册(非必需)
示例:// src/Event/ProjectCreatedEvent.php
namespace App\Event;
use Symfony\Contracts\EventDispatcher\Event;
use App\Entity\Project;
final class ProjectCreatedEvent extends Event
{
public function __construct(private Project $project) {}
public function getProject(): Project { return $this->project; }
}
在业务逻辑中调度事件
事件不能自己触发,必须由服务显式分发。通常在控制器、命令或领域服务中调用 EventDispatcherInterface:
- 注入
$dispatcher: EventDispatcherInterface到方法参数或构造函数 - 实例化事件对象,传入上下文数据
- 调用
$dispatcher->dispatch($event)—— 注意:传对象,不是字符串
示例(在服务中):public function createProject(array $data, EventDispatcherInterface $dispatcher): Project
{
$project = $this->projectRepository->save(new Project($data));
$dispatcher->dispatch(new ProjectCreatedEvent($project)); // ✅ 对象分发
return $project;
}
编写监听器并自动注册
监听器是普通 PHP 类,推荐使用 __invoke() 方式,配合属性标签自动注册:
- 类加
#[AsEventListener]属性,指定监听的事件类或事件名 - 实现
__invoke(EventType $event),类型提示确保 IDE 和运行时安全 - 无需手动写 YAML 配置(启用 autoconfigure 后自动发现)
- 支持优先级(priority=10)、多事件复用(多个 #[AsEventListener])
示例:// src/EventListener/LogProjectCreationListener.php
namespace App\EventListener;
use App\Event\ProjectCreatedEvent;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
#[AsEventListener(event: ProjectCreatedEvent::class)]
final class LogProjectCreationListener
{
public function __invoke(ProjectCreatedEvent $event): void
{
\error_log('项目已创建:' . $event->getProject()->getName());
}
}
补充:监听内置事件(如 kernel.request 或 kernel.exception)
这些是框架生命周期事件,无需自定义类,直接监听即可:
- 监听 kernel.request:适合请求预处理(权限检查、日志记录)
- 监听 kernel.response:适合响应后处理(添加 Header、压缩)
- 监听 kernel.exception:统一异常捕获与错误响应生成
- 监听器同样可用
#[AsEventListener],例如#[AsEventListener(event: 'kernel.exception')]











