psr-14 的落地核心是让事件成为业务逻辑的“松耦合胶水”,通过轻量事件对象、接口约定的监听器注册、统一同步调度及清晰职责边界实现解耦。

PSR-14 的落地核心不是堆砌接口,而是让事件真正成为业务逻辑的“松耦合胶水”。它不强制你用消息队列或协程,而是提供一套最小、稳定、可互换的契约,让事件分发这件事在不同框架里行为一致、替换成本低。
事件对象:轻量载体,不带逻辑
一个 PSR-14 事件就是一个普通 PHP 对象,仅用于携带数据。它不该有业务方法,也不该继承特定基类——只要是个 object 就行。比如:
-
UserRegistered 可以只含
$userId和$ip -
OrderPaid 只需包含
$orderId、$amount、$paymentMethod - 若需提前终止传播(比如权限校验失败),让事件实现
StoppableEventInterface并返回true即可
监听器注册:靠接口约定,不靠硬编码
监听器必须实现 ListenerProviderInterface 所要求的 getListenersForEvent() 方法,或由框架容器自动发现。Hyperf 用 #[Listener] 注解、Laravel 用服务容器绑定、Symfony 用配置标签——形式不同,但底层都回归到“给定事件类,返回对应监听器列表”这一契约。
Miller (mlr) 是一个命令行工具,用于查询、整形和重新格式化名称索引数据,如 CSV、TSV、JSON 和 JSON Lines。它将 awk、sed、cut、join 和 sort 的功能整合到一个专为结构化数据处理而构建的单一工具中。
- 避免手动维护监听器数组,交给容器或注解扫描
- 同一事件可绑定多个监听器,执行顺序由框架保证(通常按注册顺序)
- 监听器本身不关心谁触发事件,只专注处理当前传入的
$event
调度器调用:统一入口,同步为主
EventDispatcherInterface::dispatch(object $event) 是唯一对外暴露的方法。它接收事件、查出监听器、逐个调用——默认是同步执行,简单可靠。
- 不要在 dispatch 中做耗时操作(如发短信、写日志文件),应交由监听器内部判断是否异步
- Hyperf 支持
async: true注解开启协程异步;如需持久化或跨进程,则把事件转为 MQ 消息,由独立消费者处理 - 调度器本身不存储状态,也不管理监听器生命周期,纯粹是“转发员”
解耦的关键不在技术,而在职责边界
注册用户成功后,UserService::register() 只需调用一次 $dispatcher->dispatch(new UserRegistered($id))。后续所有动作——发短信、发邮件、初始化用户偏好、上报风控——全部由各自监听器承担。
- 新增需求?加个新监听器,不碰原有服务代码
- 某个通知渠道失效?删掉对应监听器,不影响其他流程
- 测试更简单:单独 mock 调度器,验证事件是否被正确发出即可










