Laravel怎么使用事件系统_Laravel Event与Listener教程【解耦】

7次阅读

laravel事件系统用于解耦旁路动作,如订单创建后发短信、写日志等;应以“发生了什么事”定义事件(如ordercreated),用监听器(如sendsmsnotification)处理;需注意队列配置、数据显式传递、避免请求/会话依赖,并区分强一致性场景是否适用。

Laravel怎么使用事件系统_Laravel Event与Listener教程【解耦】

Laravel 的事件系统不是“必须用”,而是“该用时不用就容易耦合”——比如订单创建后发短信、写日志、更新库存,全塞在控制器里,改一个逻辑就得动整个方法。

怎么注册事件和监听器

别先写代码,先想清楚:这个动作是不是“发生了什么事”,而不是“我要做什么”。比如 OrderCreated 是事件,SendSmsNotificationLogOrderActivity 才是监听器。

  • php artisan make:Event OrderCreated 生成事件类,它默认是空的,只负责携带数据(比如 $order 实例)
  • 监听器用 php artisan make:listener SendSmsNotification --event=OrderCreated,这样会自动在 EventServiceProvider$listen 数组里配好映射
  • 手动注册也行,但别漏掉 EventServiceProvider::boot() 里的 Event::listen(...) 调用,否则监听器根本不会被触发

事件触发时为什么监听器没执行

最常见的是队列配置问题:你写了 dispatch(new OrderCreated($order)),但监听器没跑,大概率是因为事件没进队列,或者队列根本没跑。

  • 检查 config/events.php 里的 'default' => 'sync' —— 如果是 sync,监听器会同步执行;改成 redisdatabase 就要确保队列服务已启动(php artisan queue:work
  • 监听器类里如果用了 ShouldQueue 接口,但没配队列驱动,它就静默失败,不会报错
  • 事件类没实现 ShouldBroadcast 却调用了 broadcast(),也会中断流程,但错误可能被吞掉

监听器里访问请求或 session 会出问题

因为事件可能异步执行,而 request()session() 在队列任务里不可用——它们绑定的是原始 http 请求生命周期,队列进程是独立的 PHP 进程。

  • 必须把需要的数据显式传进事件构造函数,比如 new OrderCreated($order, $userId, $ip),别在监听器里临时去查
  • 不要在监听器里调 auth()->user(),用户可能已登出,或根本没登录上下文;改用事件携带的 $userId 去查用户
  • 日志里想记请求路径?得提前存到事件属性里,$this->url = request()->fullUrl(),不然队列里拿不到

什么时候不该用事件系统

不是所有“之后要做点什么”的场景都适合事件。核心判断标准是:这件事是否和当前业务主流程强相关、是否要求强一致性、是否需要事务回滚联动。

  • 扣减库存必须和订单创建在同一个事务里,用事件 + 队列就可能超卖——这时候应该用数据库事务+锁,而不是 OrderCreated
  • 给用户发欢迎邮件可以异步,但修改用户邮箱后立刻发验证邮件,最好同步发,避免用户以为没生效
  • 监听器里再抛出未捕获异常,会导致整个队列任务失败卡住,得加 try/catch 并记录错误,不能依赖框架兜底

事件真正的价值不在“解耦”这个词本身,而在让你能清晰区分“核心路径”和“旁路动作”。一旦开始往监听器里塞数据库写操作、API 调用、甚至重试逻辑,就说明边界已经模糊了——这时候该回头看看,是不是把本该在领域层做的事,丢给了事件系统硬扛。

text=ZqhQzanResources