observer类不必继承modelobserver;laravel仅要求方法名匹配事件名(如created)、参数为对应模型实例,且注册时用booted更安全,因依赖已就绪;saving可中断事务,saved则确保数据已落库。

Observer类必须继承 ModelObserver 吗?
不用。Laravel 的 Observer 本质是普通 PHP 类,只要方法名匹配模型事件(如 created、updated),就能被自动调用。框架不校验父类,也不强制实现接口。写成 class UserObserver 空类完全合法。
常见错误现象:有人照着旧文档加了 extends ModelObserver,结果报 Class 'App\Observers\ModelObserver' not found——因为这个类根本不存在于 Laravel 10+ 中。
实操建议:
- 直接定义普通类,比如
app/Observers/UserObserver.php - 方法名严格对应事件名:一个模型新增后触发
created(),不是onCreated()或handleCreated() - 方法参数必须是对应模型实例,例如
public function created(User $user),类型提示不能错
注册 Observer 时 booted 和 booting 哪个时机更安全?
用 booted。模型的静态 booting 钩子在类加载时就执行,此时服务容器可能还没完全就绪;而 booted 在第一次被解析后触发,能确保依赖(如日志、队列、DB)可用。
使用场景:你在 Observer 里调用了 Log::info() 或 dispatch 了一个 job,如果注册在 booting,可能因日志通道未初始化而静默失败。
实操建议:
- 在
AppServiceProvider::boot()里注册:User::observe(UserObserver::class) - 不要在模型自身的
boot()方法里调用observe(),容易循环依赖或重复绑定 - 多个 Observer 按需注册,别一股脑全塞进一个
observe()调用里
saving 和 saved 的区别不只是“前后”那么简单
区别在于事务上下文和可中断性。saving 在事务内、可返回 false 中断保存;saved 在事务提交后触发,无法阻止写入,但能确保数据已落库。
性能影响:在 saving 里做耗时操作(如远程 API 调用)会拖慢整个事务,还可能因超时导致数据库锁等待;saved 更适合发通知、写日志、触发异步任务。
实操建议:
- 需要校验/修改即将入库的数据 → 用
saving,但只做轻量逻辑 - 要发邮件、推消息、更新搜索索引 → 用
saved,并配合dispatch(new SendWelcomeEmail($user)) - 避免在
saving里调用$model->save(),会造成无限递归
Observer 里访问 $model->getOriginal() 总是空?
因为 created 事件中,模型刚从数据库取回,original 和 attributes 是一致的;而 updated 事件里,getOriginal() 才真正反映变更前的值——但前提是模型开启了脏检查(默认开启)且字段确实变了。
容易踩的坑:有人在 updated 里直接比对 $model->name !== $model->getOriginal('name'),却发现恒为 false。原因可能是模型没设置 $fillable,或者更新时用了 update(['name' => 'x']) 但没触发模型事件(比如绕过了 Eloquent,用了 Query Builder)。
实操建议:
- 确认更新操作走的是模型方法:
$user->update(...)或$user->save(),而不是DB::table()->where()->update() - 调试时打印
$model->isDirty()和$model->getChanges(),看是否真有变更 - 不要依赖
getOriginal()判断“是否首次设置”,它不反映业务意义上的“空值转非空”,只反映 Eloquent 记录的上一次状态










