Observer不触发90%是注册失败,需显式调用Model::observe(),确保注册位置正确、类名严格匹配(如Post对应PostObserver),并在AppServiceProvider::boot()或模型boot()中注册。

Observer 类写好了但完全没反应,先查注册是否真的生效
Observer 不触发,90% 是注册环节失败。Laravel 从不自动扫描 app/Observers/ 目录,文件存在 ≠ 它被绑定。必须显式调用 Model::observe(),且注册位置、时机、类名三者缺一不可。
常见错误包括:
- 把
User::observe(UserObserver::class)错写在EventServiceProvider::$listen里——那是给Event::dispatch()用的,和 Observer 无关 - 在
AppServiceProvider::boot()里注册时,模型类尚未加载(比如用了延迟加载或未加use),导致反射失败 - 类名不严格匹配:模型叫
Post,Observer 必须叫PostObserver;postObserver、Postobserver、PostsObserver全部无效 - Laravel 13 中若模型有自定义
boot()方法,且内部已调用过static::created()等静态监听,再调observe()可能被覆盖(建议统一用一种注册方式)
怎么快速验证 Observer 是否已注册成功
最直接的办法是临时加一行日志到 Observer 构造函数或任意方法里,然后手动触发一次模型操作(如 User::create([...])),看日志是否输出。如果没输出,说明根本没实例化 Observer 对象——注册失败。
更底层的验证方式是检查模型的事件监听器列表:
php artisan tinker > \App\Models\User::getObservableEvents() > \App\Models\User::getBootedModels() // 看是否包含 User
或者在代码中 dump:
\Log::debug('User observers: ', \App\Models\User::getDispatchesEvents());
注意:getDispatchesEvents() 返回空数组,大概率是没注册;返回了事件映射但依然不触发,就要查 Observer 方法签名是否正确(如 creating() 必须接收 $model 参数)。
Laravel 13 中注册位置和方式的几个关键变化
Laravel 13 没有取消 Observer 注册机制,但对启动顺序更敏感。推荐以下两种可靠注册方式:
- 在
AppServiceProvider::boot()中注册,且确保use语句完整、模型类已加载:use App\Models\User;<br>use App\Observers\UserObserver;
然后User::observe(UserObserver::class); - 在模型自己的
boot()方法里注册(适合强耦合场景):protected static function boot()<br>{<br> parent::boot();<br> static::observe(UserObserver::class);<br>}
避免在 EventServiceProvider 的 $subscribe 数组里注册 Observer——那是给事件订阅者(Subscriber)用的,不是 Observer。
批量操作、测试环境、软删除这些场景下 Observer 天然不触发
即使注册完全正确,以下情况 Observer 也必然不触发,这不是 bug,是设计如此:
-
User::where('id', 1)->update(['name' => 'x'])、User::upsert()、DB::table('users')->update()—— 全部绕过模型生命周期,Observer 无感知 - PHPUnit 测试中默认禁用模型事件,需显式调用
$this->withEvents()(Laravel 13+)或\Event::fake()后再验证 - 软删除只触发
deleting/deleted;硬删(forceDelete())才触发forceDeleting/forceDeleted -
saving和saved的事务阶段差异极大:saving可改属性或返回false中断保存;saved已提交,改字段再save()不会写回数据库
真正容易被忽略的是:Observer 方法内不做守卫判断,就直接执行耗时逻辑(比如 HTTP 请求、嵌套 save)。Laravel 13 对这类操作没有兜底保护,出错只会静默失败或引发事务异常。


















