模型观察者需手动注册,方法名须严格匹配生命周期钩子;saving适合保存前修改字段并阻塞执行;关联模型变更不触发其观察者;发邮件等耗时操作应交由队列处理。

模型观察者没生效?先确认是否注册到服务提供者
模型观察者不会自动运行,必须显式注册。最常见问题是只写了 App\Observers\UserObserver 类,却忘了在 AppServiceProvider::boot() 里调用 User::observe(UserObserver::class)。
注意:Laravel 9+ 支持批量注册,但前提是模型类名和观察者类名遵循约定(如 User 对应 UserObserver),否则仍需手动绑定:
use App\Models\User; use App\Observers\UserObserver; User::observe(UserObserver::class);
- 多个模型共用一个观察者?可以传数组:
User::observe([UserObserver::class, AuditObserver::class]) - 观察者方法名必须严格匹配生命周期钩子(
created、updated、saving等),大小写敏感 - 如果模型用了软删除,
deleted不会触发,要改用forceDeleted或监听trashed
想在保存前修改字段?优先用 saving 而非 creating
creating 只在 create() 静态方法或新建实例后调用 save() 时触发;而 saving 在每次 save()(包括更新)前都执行,覆盖场景更全。
比如自动填充 slug 字段:
public function saving(User $user)
{
if (empty($user->slug)) {
$user->slug = Str::slug($user->name);
}
}
-
saving中修改属性会直接进入当前保存事务,无需额外save() - 若在
saving中抛出异常(如验证失败),整个保存会被中止 - 避免在
saving里做耗时操作(如 HTTP 请求),它阻塞主流程
关联数据变更不触发观察者?因为观察者只监听目标模型
模型观察者不会递归监听关联模型。例如 Post 观察者里的 deleted 方法,不会因 $post->comments()->delete() 而触发 Comment 的观察者。
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
常见误判场景:
- 用
post()->delete()删除文章 → 触发Post::deleted - 但
$post->comments是 Eloquent 集合,遍历调用$comment->delete()才会逐个触发Comment::deleted - 若用
Comment::where('post_id', $post->id)->delete()(原生 SQL 删除),则完全绕过模型生命周期,观察者彻底失效
需要联动处理时,要么在父模型观察者中手动触发子逻辑,要么改用事件系统(event(new PostDeleted($post)))解耦。
观察者里发邮件/调 API 失败?别在同步上下文中做异步事
所有观察者方法默认在数据库事务内同步执行。如果在 created 里调 Mail::to(...)->send(...),一旦邮件发送超时或报错,整个事务会回滚——用户注册成功页面显示失败,但数据库其实已插入。
- 正确做法是分发队列任务:
SendWelcomeEmail::dispatch($user)->onQueue('mail') - 确保队列驱动已配置(
redis或database),且队列进程正在运行 - 不要在观察者里用
sleep()、file_get_contents()等阻塞操作
真正容易被忽略的是:观察者方法里不能访问未加载的关联关系(如 $user->profile->avatar),除非提前用 with() 加载,否则会 N+1 查询或报错。

















