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

Observer 类没被自动注册?检查 EventServiceProvider 是否手动绑定了
Laravel 不会自动发现并加载 Observer,哪怕你把它放在 app/Observers 下、命名规范也对。必须显式注册到 EventServiceProvider 的 $listen 或通过 observe() 方法绑定。
常见错误现象:created、updated 等方法完全不触发,模型操作日志里看不到 Observer 输出,调试断点也不进。
- 用
php artisan make:observer UserObserver --model=User生成后,别忘了在App\Providers\EventServiceProvider的boot()里加:public function boot(): void { User::observe(UserObserver::class); } - 如果一个 Observer 要监听多个模型,每行单独调用
observe(),不能传数组 -
observe()必须在模型类已加载之后调用(比如放在boot()里),否则会报Class 'User' not found
creating 和 created 的区别:事务中失败时行为完全不同
这两个钩子看似只差个 “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(),确保读到最新状态 - 用
DatabaseTransactionstrait 时,Observer 触发的 DB 操作也会被回滚,但外部服务调用(如发短信、调 API)不会——得用 Mock 隔离 - 生产环境禁用 Observer 的最简方式:注释掉
EventServiceProvider里的observe()调用,比删文件更安全










