laravel 10+ 模型事件必须在 booted() 中注册,boot() 已失效;created/updated 等静态方法需置于 booted() 内,且批量操作、原生 sql 等绕过 eloquent 的方式不触发事件。

直接用 booted(),别碰 boot() —— Laravel 10+ 之后,模型事件注册逻辑已移至实例化后的生命周期钩子,boot() 里写的 created()、saving() 全部静默失效。
为什么 boot() 不再触发模型事件
因为 Laravel 10+ 把事件监听器的注册时机从“类加载时”改成了“模型实例首次创建后”。boot() 是静态方法,只在类加载阶段执行一次,此时模型实例还没诞生,static::created() 等调用看似成功,实则没绑定到任何实例上。
-
booted()是 protected static function,必须定义在模型类内部 - 所有
static::created()、static::updated()等必须写在booted()内部 - 若用了 trait 或基类复用逻辑,记得在子类
booted()中显式调用parent::booted() - 常见错误:模型没
use Illuminate\Database\Eloquent\Model;,导致static::调用失败且无报错
saved() 和 updated() 到底怎么选
saved() 在 INSERT 和 UPDATE 两种 SQL 操作后都触发;updated() 只有在已有主键、且至少一个字段值真正变化时才触发(即底层执行了 UPDATE 语句)。
- 新建用户要发欢迎邮件?用
created(),别指望updated()或saved()覆盖 - 只想在邮箱字段被改时同步第三方系统?加判断:
if ($user->isDirty('email')) { ... } - 在
saved()里调$model->refresh()可能引发无限 save 循环,尤其配合自动填充字段时 -
updateOrCreate()和upsert()不触发creating()/updating(),只可能进saved()
批量操作为何完全不触发事件
像 User::insert([...])、User::upsert(...)、User::where(...)->update(...) 这些方法绕过 Eloquent 实例化流程,直接执行 SQL,连模型对象都不生成,自然没有事件可监听。
- 需要日志或副作用?改用循环 +
new User()->save(),但注意性能损耗 - 大批量导入场景,优先考虑禁用事件:
User::withoutEvents(fn () => User::insert(...)) -
observe(null)可临时解除观测器,但仅对当前模型实例有效,不适用于静态批量方法 - 软删除恢复(
$model->restore())会触发restored(),但where(...)->update(['deleted_at' => null])不会
最易被忽略的一点:监听器是同步执行的,里面调外部 API 或复杂计算会卡住请求。真要发邮件、推通知,必须 dispatch Job,别在 created() 里直接 Mail::to(...)->send()。











