模型事件仅在调用save()、delete()等模型方法时触发,Db类操作不触发;须在模型类protected static function init()中注册;before_*返回false可中断操作;after_insert中主键需用getPk()动态获取;批量操作只触发一次回调。

模型事件只在调用 save()、delete()、destroy() 等模型方法时触发,用 Db 类直接操作数据库完全不会触发——这点不搞清,写半天回调也白搭。
模型事件必须在 init() 静态方法里注册
不是构造函数,不是控制器里,也不是随便哪个方法里。必须是模型类的 protected static function init(),否则不生效。
-
self::beforeInsert()和self::event('before_insert', ...)效果一致,推荐用快捷方法,更直观 - 回调函数第一个参数固定是当前模型实例(如
$user),可直接读写属性,比如$user->status = 1 - 如果在
before_*类事件中返回false,整个操作会中断,数据库写入不会发生 - 多个同名事件可以叠加注册,执行顺序按注册先后,但别依赖顺序做关键逻辑
after_insert 拿不到刚生成的 ID?
在 after_insert 回调里,$user->id 是可用的;但如果模型主键不是 id 或用了自定义主键名(比如 uid),得用 $user->getPk() 动态获取字段名再取值。
- 别直接写死
$user->id,尤其当表结构可能变化时 - 如果用了软删除或时间戳自动写入,这些字段在
after_insert里也已同步到模型实例中 - 想记录日志或关联写入,优先用
$user->getData(),它返回的是最终写入数据库的完整数据数组
为什么 isUpdate() 不触发模型事件?
因为 isUpdate(true) 是给 save() 方法传参用的控制标记,本身不触发任何事件;真正触发事件的是 save() 执行那一刻。如果你在控制器里写了:
立即学习“PHP免费学习笔记(深入)”;
$user = new User(); $user->isUpdate(true)->save(); // ❌ 这里 isUpdate() 只是链式调用设置标志
事件依然走 before_update / after_update,但前提是这个 save() 真的执行了更新动作——也就是主键存在且有脏数据。
-
isUpdate()不是独立操作,它没有自己的事件钩子 - 别在事件回调里再调
$model->save(),容易引发递归或事务冲突 - 想区分新增/更新逻辑,直接在
before_write里用$model->exists()判断更可靠
最常被忽略的一点:模型事件对批量操作(如 User::destroy([1,2,3]))只触发一次回调,参数是第一个被处理的模型实例,不是数组。需要逐条处理的逻辑,得自己循环 + 单条 save() 或 delete()。



















