Skip to main content

什么是事件

Laravel 的事件系统实现了简单的观察者模式。 在应用中触发(dispatch)事件,再定义响应这些事件的监听器,可以把组件间的耦合降到最小。 例如触发「订单已确认」事件后,「发送确认邮件」「减少库存」「向 Slack 通知」等多个监听器可以独立运行。 订单处理代码完全不需要知道邮件或 Slack 的实现。
事件类放在 app/Events,监听器放在 app/Listeners。 目录不存在时 Artisan 命令会自动创建。

生成事件与监听器

不带参数运行会进入交互式提示:

注册事件

事件自动发现

默认情况下,Laravel 会扫描 app/Listeners 自动注册监听器。 它会读取 handle__invoke 方法的参数类型来推断事件映射。
使用 PHP union 类型可以让同一方法处理多个事件:
若监听器放在其他目录,在 bootstrap/app.php 中额外指定扫描位置:
通配符可指定多个目录:
查看已注册的监听器:
生产环境建议缓存监听器清单以提升性能。部署时运行 php artisan optimizephp artisan event:cache。 清除缓存用 php artisan event:clear

手动注册

也可以在 AppServiceProviderboot 中通过 Event 门面手动注册:
也可以用闭包:

定义事件

事件类是数据的容器,不含逻辑,只以属性形式承载信息:
SerializesModels trait 让排队的监听器在序列化事件时能正确处理 Eloquent 模型。

触发事件

使用 dispatch 静态方法或 event() 辅助函数触发事件:
也有按条件触发的方法:

事务提交后触发

若希望仅在数据库事务提交后触发,让事件类实现 ShouldDispatchAfterCommit。 事务失败则事件会被丢弃:

编写监听器

监听器通过 handle 方法接收事件。构造器中的依赖由服务容器自动注入:
handle 方法返回 false 可以阻止事件继续传给后续监听器。

排队监听器

发送邮件、发起 HTTP 请求等耗时操作可以作为排队监听器异步执行。 只需实现 ShouldQueue,事件触发时监听器会自动入队。
使用排队监听器前需配置队列并启动 worker。详见队列与任务

事件监听器的防抖

当同一事件在短时间内多次触发,而你只想处理最后一次事件时,为排队监听器添加 DebounceFor 属性可以将指定时间内的事件合并处理。
在此示例中,如果同一商品的 ProductUpdated 事件在 30 秒内反复触发,监听器会被防抖,只处理最后一次事件。具有不同 debounceId 的事件会各自独立处理。 若要限制频繁触发的事件推迟监听器执行的时间上限,可以指定 maxWait
可以通过 debounceVia 方法更改用于追踪防抖状态的缓存存储,该方法会接收事件作为参数。
防抖监听器与唯一监听器无法一同使用。不要在使用 DebounceFor 属性的监听器上实现 ShouldBeUnique。当从多台 Web 服务器或容器触发事件时,请让所有服务器使用同一个共享缓存服务器。

自定义队列连接 / 名称 / 延迟

用 PHP 属性设置:
也可以用方法动态返回:

最大重试次数与超时

#[Tries]#[Timeout] 控制失败行为:

失败处理

定义 failed 方法处理超过最大重试仍失败的情况:

事件订阅者

事件订阅者用来把相关的多个事件处理器组织在一个类中。

创建订阅者

subscribe 方法返回事件与处理函数的映射数组:

注册订阅者

若启用事件自动发现,返回数组的 subscribe 会被自动注册。 手动注册在 AppServiceProvider::boot 中调用 Event::subscribe

实践示例:用户注册时发送欢迎邮件

1

创建事件类

编辑 app/Events/UserRegistered.php 添加用户属性:
2

创建监听器

实现 ShouldQueue,让发邮件异步处理:
3

在控制器中触发

在用户注册后调用 UserRegistered::dispatch()
控制器只负责触发事件,不关心邮件发送的实现。 未来若要加上 Slack 通知,控制器无需改动。
4

启动 worker

启用事件自动发现后无需在 AppServiceProvider 中手动注册。放在 app/Listeners 中的类会被自动识别。
使用 php artisan event:list 查看已注册的事件和监听器,定期检查是否有意外注册。
最后修改于 2026年8月21日