Laravel怎么使用观察者(Observer)_Laravel模型事件监听教程【追踪】

6次阅读

laravel observer 必须手动注册到 eventserviceprovider,否则不会触发;creating 在保存前可中断操作,created 在入库后执行但事务未提交;observer 方法只接收模型实例,需用 getoriginal() 获取原始值。

Laravel怎么使用观察者(Observer)_Laravel模型事件监听教程【追踪】

Observer 类没被自动注册?检查 EventServiceProvider 是否手动绑定了

Laravel 不会自动发现并加载 Observer,哪怕你把它放在 app/Observers 下、命名规范也对。必须显式注册到 EventServiceProvider$listen 或通过 observe() 方法绑定。

常见错误现象:createdupdated 等方法完全不触发,模型操作日志里看不到 Observer 输出,调试断点也不进。

  • php artisan make:observer UserObserver --model=User 生成后,别忘了在 AppProvidersEventServiceProviderboot() 里加:
    public function boot(): void {     User::observe(UserObserver::class); }
  • 如果一个 Observer 要监听多个模型,每行单独调用 observe(),不能传数组
  • observe() 必须在模型类已加载之后调用(比如放在 boot() 里),否则会报 Class 'User' not found

creatingcreated 的区别:事务中失败时行为完全不同

这两个钩子看似只差个 “d”,但执行时机和可靠性差异极大——creating 在保存前触发,可修改属性或返回 false 中断保存;created 在数据已写入数据库后触发,此时事务可能还没提交。

使用场景:想阻止非法创建?用 creating;想发通知、写日志、更新关联缓存?优先选 created,但要注意事务未提交时其他进程查不到新数据。

  • creating 中修改 $model->status = 'pending' 会生效;created 中改则无效(已落库)
  • created 里调用 DB::transaction() 嵌套事务?Laravel 默认不支持,会抛 LogicException
  • 若需强一致性(如同时写日志表+主表),建议把逻辑移到事件监听器(ModelCreated)而非 Observer,更易控制事务边界

Observer 方法接收的参数是模型实例,不是 ID 或数组

新手常误以为 created 回调会传入 ID 或原始数据,实际只传一个已加载的完整模型对象,且该对象的 $casts$appends访问器Accessors)都已生效。

容易踩的坑:直接拿 $user->password 想取明文?不行——Eloquent 默认不会把加密后的密码字段解密;想取 $user->full_name(访问器)?可以,但注意它不参与数据库查询。

  • 要获取原始数据库值(绕过访问器),用 $user->getOriginal('name')
  • 要判断字段是否被修改过(比如只在邮箱变更时发验证邮件),用 $user->isDirty('email')$user->getChanges()
  • 避免在 updating 里调用 $model->save(),会导致无限循环 + Maximum function nesting level reached

测试 Observer 时,别漏掉 refresh() 和事务回滚影响

PHPUnit 测试里用 create() 新建模型后,Observer 的 created 会执行,但如果你紧接着查数据库(比如 User::first()),可能拿到的是旧缓存结果,尤其开启 Query Cache 或用了 remember()

性能影响:Observer 是同步执行的,每个模型操作都会多一次 PHP 方法调用;高并发写入场景下,如果 Observer 里有 http 请求或慢 sql,会拖慢主流程。

  • 测试中验证 Observer 行为,记得在断言前加 $user->refresh(),确保读到最新状态
  • DatabaseTransactions trait 时,Observer 触发的 DB 操作也会被回滚,但外部服务调用(如发短信、调 API)不会——得用 Mock 隔离
  • 生产环境禁用 Observer 的最简方式:注释掉 EventServiceProvider 里的 observe() 调用,比删文件更安全

事情说清了就结束。Observer 看似简单,但事务边界、参数生命周期、测试隔离这三点,线上出过太多隐蔽问题。

text=ZqhQzanResources