observer方法名必须严格匹配事件名且首字母小写,如created;注册须在模型类加载后,推荐用eventserviceprovider的$observe属性;retrieved易致性能问题,耗时操作应交由队列处理。

Observer 方法名必须严格匹配事件名,且首字母小写
Observer 不是靠注解或配置驱动的,它依赖 Laravel 对方法名的反射调用。比如你想监听模型创建后的逻辑,必须定义 created 方法(不是 Created、onCreated 或 handleCreated)。Laravel 会自动把 User::create() 后触发的事件映射到观察者里同名的 public 方法上。
常见错误现象:retrieved 方法写了但日志没输出;updating 没生效——大概率是拼错了方法名,或加了多余参数(如 public function updated(User $user, $event)),而 Laravel 只传模型实例,不传事件对象。
-
creating/created:仅对create()或save()新记录有效;update()不触发 -
updating/updated:只在字段实际变更时触发(基于isDirty()),但touch()、increment()等操作不会走这些钩子 -
saving/saved:覆盖创建+更新,适合通用前置校验或统一埋点 -
deleting/deleted:硬删才触发;软删除需额外实现forceDeleting才能拦截forceDelete()
注册 Observer 必须在模型类加载后执行,否则静默失效
很多人把 User::observe(UserObserver::class) 写在 AppServiceProvider::boot() 顶部,结果发现没反应——因为此时 User 类可能还没被自动加载,静态调用失败,Laravel 不报错也不提示。
正确做法是确保模型类已加载后再注册。最稳妥的方式是在 boot() 末尾或使用延迟闭包:
public function boot()
{
// ✅ 推荐:显式 use,保证类加载
use App\Models\User;
use App\Observers\UserObserver;
User::observe(UserObserver::class);
}
如果你用的是 Laravel 9+,还可以改用 EventServiceProvider 的 $observe 属性注册,更集中、更安全:
// app/Providers/EventServiceProvider.php
protected $observe = [
User::class => [UserObserver::class],
];
- 手动注册时,别在模型的
boot()静态方法里调observe(),那会形成循环依赖 - 多个 Observer 可同时注册:
User::observe([AObserver::class, BObserver::class]) - 注册后无法取消(除非手动
User::flushEventListeners()),测试时注意隔离
retrieved 事件极易引发性能问题,慎用或主动屏蔽
retrieved 是唯一在「读取」阶段触发的事件,但它会在每次 get()、first()、paginate() 中的每条记录上都执行一次。查 100 条用户?它就调 100 次——哪怕你只是想在编辑单条时打个日志。
典型翻车场景:在 retrieved 里写 Log::info() 或调外部 API,结果首页分页一卡顿,监控里全是慢日志。
- 真正需要时再启用:比如只在后台编辑页查单条,可用
withoutEvents()全局禁用,再局部开启 - 替代方案:用访问器(accessor)或资源(Resource)做展示层处理,别把展示逻辑塞进数据层
- 如果非要用,务必加条件判断:
if (request()->routeIs('users.edit')) { ... },但不如直接移出 Observer
耗时操作必须丢进队列,Observer 本身不支持异步
Observer 方法运行在 HTTP 请求生命周期内,同步执行。你在 created 里发邮件、调短信网关、生成缩略图,都会拖慢接口响应,甚至超时。
正确姿势是立刻 dispatch 一个 job,让队列 worker 异步处理:
public function created(User $user)
{
SendWelcomeEmailJob::dispatch($user)->onQueue('emails');
}
别在 Observer 里写 sleep()、file_get_contents()、DB::transaction() 套娃等阻塞操作——它不是事务边界,也不是任务调度器。
- Observer 是轻量级生命周期钩子,不是业务服务入口
- 涉及跨模型、跨服务、重计算的逻辑,应抽成 Service 类,再由 Observer 或事件监听器调用
- 如果要保证顺序(如先发短信再写日志),别依赖 Observer 方法顺序,用数据库状态 + 队列链式调度










