优先级数值越大监听器越先执行,设错会导致库存超卖、风控失效;支持任意整数(如100、0、-50),正数用于强依赖操作,负数用于弱依赖环节,禁止使用浮点数或字符串。

优先级数值越大,监听器越先执行;设错会导致业务逻辑错乱,比如库存超卖、风控失效。
addListener 里直接传整数优先级
这是最直白的写法,适合快速验证或小型项目。第三个参数就是优先级,必须是整数:
$dispatcher->addListener('order.paid', [$this, 'deductStock'], 100);
- 数值支持任意整数,
100、0、-50都合法 - 正数建议用于强依赖顺序的操作(如扣减、校验),负数留给异步通知、日志等弱依赖环节
- 匿名函数也一样:
$dispatcher->addListener('user.login', function ($e) { ... }, 80) - 别用浮点数或字符串——
addListener第三个参数类型声明是int,传错会触发类型错误
EventSubscriberInterface 中定义优先级数组
中大型项目推荐这种方式,把优先级和事件绑定关系写死在类里,结构清晰、易检索:
public static function getSubscribedEvents(): array
{
return [
'order.paid' => ['onPaid', 90],
'order.cancelled' => ['onCancelled', -20],
];
}
- 数组值必须是
[方法名, 优先级]形式,不能只写方法名 - 同一个类监听多个事件时,各事件的优先级互不影响
- 如果某个事件要注册多个处理方法,可以写成
'order.paid' => [['onPaid', 90], ['sendReceipt', 30]] - 注意:返回数组里键名是事件名,不是事件对象类名
服务标签方式(YAML/XML)配置 priority
适合统一治理、不希望改 PHP 代码的场景,尤其在团队协作或微服务拆分后:
services:
App\EventListener\StockDeductionListener:
tags:
- { name: 'kernel.event_listener', event: 'order.paid', method: 'onPaid', priority: 100 }
-
priority字段必须是整数,YAML 里写priority: 100没问题,但别写成priority: '100'(字符串会被当成 0) - XML 写法类似:
<tag name="kernel.event_listener" event="order.paid" method="onPaid" priority="100"></tag> - 第三方 Bundle 注册的监听器也会出现在这里,
bin/console debug:event-dispatcher order.paid能看到它们的priority值 - 同个服务打多个标签监听同一事件?不行,容器编译会报重复注册错误
同优先级时谁先执行?注册顺序决定一切
这点最容易被忽略:当两个监听器都设了 50,谁先跑不是看文件名、类名或字母顺序,而是看「谁先被注册」:
- 手动调用
addListener的顺序 = 执行顺序 - 服务标签注册的顺序 = YAML 文件里服务定义的先后顺序(不是文件加载顺序)
- 订阅器(
EventSubscriberInterface)内部多个事件之间不互相影响,但同一事件下多个方法若优先级相同,按getSubscribedEvents()数组键的遍历顺序执行 - 调试时用
bin/console debug:event-dispatcher order.paid输出的列表顺序,就是实际执行顺序
真正麻烦的是跨服务、跨 Bundle 的隐式注册——你改了一个监听器的 priority,可能只是把问题从“执行太晚”变成“执行太早”,而没解决根本依赖关系。优先级不是万能胶,该串行的逻辑,还是得靠领域建模收口。











