observer 必须手动注册且时机正确:在 appserviceprovider::boot() 中调用 model::observe(observer::class),注册需在模型就绪后;laravel 不自动加载,类名须严格匹配(如 post 对应 postobserver);事件监听应放在模型的 booted() 而非 boot() 中;saving 可中断保存并修改数据,saved 在事务提交后执行;批量操作不触发模型事件;软删除触发 deleting/deleted,硬删触发 forcedeleting/forcedeleted。

Observer 类写好了但事件不触发?八成是没注册,或者注册时机错了。Laravel 从不自动加载 Observer,必须手动绑定到模型,且得在模型已就绪之后执行。
Observer 必须手动注册,不能只放文件
生成 UserObserver 后,app/Observers/UserObserver.php 文件存在 ≠ 它会生效。Laravel 不扫描目录、不自动发现类。
- 正确做法:在
AppServiceProvider::boot()中调用User::observe(UserObserver::class) - 错误做法:只放文件、不注册;或在
EventServiceProvider的$listen里配(那是给事件系统用的,不是 Observer) - 如果模型类名是
Post,Observer 类名必须是PostObserver,否则反射失败,IDE 也可能报错
注册时机必须用 booted(),不是 boot()
Laravel 10+(及新版 9.x)中,模型事件监听逻辑已移到实例化后的 booted() 钩子,boot() 仅用于静态初始化,放事件监听器不会触发。
-
booted()是protected static function,必须定义在模型类内部,例如:static::created(fn ($user) => Log::debug('User created: '.$user->id)) - 不要在
boot()里写static::created(),它不会执行 - 若用 trait 复用逻辑,确保
booted()没被覆盖,必要时加parent::booted()
saving 和 saved 的事务行为完全不同
这两个钩子看似只差一个字母,但执行上下文和可靠性差异极大:
-
saving在事务内、INSERT/UPDATE 前触发,可修改字段值或返回false中断保存(比如校验必填字段) -
saved在事务提交后触发,数据已落库,适合发通知、写日志、触发队列任务 - 在
saving里调$model->save()会递归触发,导致爆栈;在saved里改属性再save()也无效(已入库)
批量更新不触发任何模型事件
User::where()->update()、DB::table()、upsert() 这些操作完全绕过 Eloquent 生命周期,Observer 对它无感。
- 想监听批量变更?要么改用模型循环 +
save()(注意 N+1),要么在业务层显式调用自定义方法 -
updated()只在真实字段变更时触发(依赖$model->isDirty()),而saved()插入和更新都触发 - 软删除走
deleting→deleted;硬删才走forceDeleting→forceDeleted,方法名一个字母都不能错
最容易被忽略的是:Observer 方法里访问 $model->getOriginal('email') 时,created 事件中它和当前值一样——只有 updated 或 deleted 才真正反映变更前状态。











