Laravel怎么实现模型观察者_Laravel监听模型创建与更新事件【源码】

2次阅读

必须在服务提供者boot()中调用model::observe()显式注册观察者;created在事务提交后触发,适合发通知;updated仅字段变更时触发,saved则每次保存都触发;关联模型需预加载或手动查询。

Laravel怎么实现模型观察者_Laravel监听模型创建与更新事件【源码】

怎么注册模型观察者(Observer)

laravel 的模型观察者不是自动生效的,必须显式注册。常见错误是写了 Observer 类但没绑定到模型,结果事件完全不触发。

  • 在服务提供者(如 AppServiceProvider)的 boot() 方法里调用 Model::observe(Observerclass::class)
  • 观察者类必须继承 IlluminatedatabaseEloquentObserversObserver 或直接定义静态方法(Laravel 9+ 支持无继承写法)
  • 不要放在 register() 里 —— 此时模型尚未加载,会报 Class 'AppModelsUser' not found
// AppObserversUserObserver.php class UserObserver {     public function created(User $user)     {         // $user 已存入数据库,主键已生成     } <pre class='brush:php;toolbar:false;'>public function updating(User $user) {     // 注意:此时 $user->isDirty('email') 可用,但 $user->getOriginal('email') 是旧值 }

}

created 和 creating 哪个更适合发通知?

creating 在写入数据库前触发,created 在事务提交后触发。选错会导致数据不一致或通知内容缺失。

  • 发短信、邮件、写日志等「依赖已持久化数据」的操作,必须用 created —— 否则可能取不到自增 ID 或关联数据
  • 需要修改即将插入的数据(比如设置默认头像 URL),用 creating;但注意它不能抛异常中断保存(除非手动 throw
  • 如果用了数据库事务且观察者里做了 DB 操作,created 更安全 —— 它在事务外执行(Laravel 10+ 默认行为),避免锁表或死锁

为什么 updated 不触发,但 saved 却能捕获?

updated 只在模型「实际字段被修改」时触发,而 saved 在每次成功保存(insert/update)后都触发。

  • $user->name = 'a'; $user->save(); → 触发 updated
  • $user->touch(); 或只改了时间戳字段 → 不触发 updated,但触发 saved
  • $user->increment('views'); → 不触发 updated(底层走的是 raw query,绕过模型事件)
  • 想监听所有变更,统一用 saved,但需自行判断:if ($user->wasChanged()) { ... }

Observer 里访问关联模型为什么总是 NULL

观察者方法接收的是当前模型实例,它默认不加载关联关系。常见错误是直接调用 $user->posts 然后报错。

  • 关联数据未预加载时,$user->posts 返回空集合或触发懒加载 —— 但观察者执行时可能已脱离请求上下文,懒加载失败
  • 解决办法只有两个:在触发事件前显式预加载(如 User::with('posts')->find($id)),或在观察者里用查询重建(Post::where('user_id', $user->id)->get()
  • 更稳妥的做法是:把需要的字段提前塞进模型,比如在 saving 里用 $user->setAttribute('last_post_title', ...),然后在 saved 里读取

模型事件本质是「钩子」,不是魔法。它不改变 Eloquent 的生命周期阶段,也不自动补全数据。什么时候查、查什么、要不要加事务,都得自己想清楚。

text=ZqhQzanResources