模型观察器需在模型首次加载前注册,方法名严格匹配事件,仅对Eloquent单条操作生效;批量更新、原生查询、事务外调用均不触发。

模型观察器不是“开了就能用”的开关,它必须注册、方法名要对、事件触发路径要走模型方法——批量操作、原生查询、事务外调用全都不触发。
observer 方法必须在模型首次加载前注册
常见失效不是代码写错,而是 AppServiceProvider::boot() 里注册太晚,或模型已被其他地方提前加载。Laravel 只在模型类第一次被引用时绑定事件监听器,之后再调用 observe() 无效。
- 确保
use App\Models\User;和use App\Observers\UserObserver;都在AppServiceProvider的use区声明 - 注册语句必须放在
boot()方法内,且不能包裹在条件判断中(如if (app()->environment('local'))) - 如果模型在服务提供者之前就被加载(比如通过配置、缓存预热),可改用模型自身的
boot()静态方法注册:static::observe(UserObserver::class)
created / updating / deleting 等方法名不能拼错
Laravel 用魔术方法匹配事件,大小写、前后缀都必须严格一致。写成 onCreated、afterCreate 或 Creating(首字母大写)都不会被调用。
- 可用的完整方法名列表:
retrieved、creating、created、updating、updated、saving、saved、deleting、deleted、restoring、restored、forceDeleting、forceDeleted - 软删除模型:触发的是
deleting/deleted,不是forceDeleting;恢复时走restoring/restored,不是updating - 方法参数必须是模型实例,类型提示可选但建议加上,例如
public function created(User $user)
saving 和 saved 的行为差异直接影响数据一致性
saving 在写入数据库前执行,可修改属性或返回 false 中断保存;saved 已落地,此时抛异常不会回滚——除非整个业务逻辑被事务包裹。
- 在
saving中校验并阻止:public function saving(User $user) { if (empty($user->email)) { return false; } } - 在
created或updated中发通知、写日志、清理缓存——这些是“已确认成功”的副作用 - 避免在
saved里再调用模型的save(),否则可能引发无限循环或死锁
批量更新、原生查询、DB门面操作完全不触发 observer
所有绕过 Eloquent 模型实例的操作,都不会经过生命周期事件调度。这是设计使然,不是 bug。
-
User::where('id', 1)->update(['name' => 'foo'])→ 不触发updating、updated -
DB::table('users')->where('id', 1)->update(...)→ 完全无事件 -
User::upsert(...)(Laravel 9.2+)→ 不触发creating/created,只触发updating/updated(如果命中已有记录) - 需要统一处理的场景,要么改用模型遍历 +
save(),要么在业务层显式补调逻辑
真正容易被忽略的点是:observer 不是全局钩子,它只对「走模型方法」的单条操作生效;而项目里大量存在的批量、队列、命令行导入,往往悄无声息地跳过了你精心写的 created 日志或 deleted 缓存清理。


















