先查后删最稳妥,因delete()立即执行致模型失效,无法获取删除前真实数据;软删需withtrashed()查询,恢复用onlytrashed()->restore()。

直接用 find() 查出来再删,是最稳妥、最可控的方式。硬要一步到位调 delete(),就拿不到旧数据了。
为什么不能先 delete() 再查?
因为 delete() 是立即执行的物理删除(或软删),执行完模型实例就失效了,$model->attributes 仍可读,但关联状态、原始数据库值可能已不同步;更关键的是,如果用了事务或触发器,中间状态不可靠。
-
User::deleteAll(['id' => 123])这类静态批量操作,压根不经过模型实例,完全没机会读旧值 -
createCommand()->delete(...)同理,绕过 AR 层,只返回影响行数 - 软删除场景下,
$model->delete()会改deleted_at,但此时再读$model->toArray()拿到的是“已删”状态,不是删除前的快照
正确做法:查出来 → 记录需要的字段 → 再删
分两步,显式控制时序,确保拿到的是删除前的真实数据:
- 用
User::findOne($id)或User::find()->where(...)->one()获取完整 AR 实例 - 立刻提取所需字段:
$oldName = $user->name、$oldEmail = $user->email,或用$user->getOldAttributes()拿数据库原始值(避免脏读) - 确认无误后调
$user->delete()(硬删)或$user->restore()(软删恢复)
示例:
$user = User::findOne(123);
if ($user !== null) {
$logData = [
'id' => $user->id,
'email_before_delete' => $user->email,
'created_at' => $user->created_at,
];
// 记入日志、发通知、写审计表...
$user->delete(); // 此时才真正删
}
软删除场景下怎么安全取“删除前”的数据?
软删记录默认被 find() 排除,必须显式启用:
- 用
User::find()->withTrashed()->where(['id' => 123])->one()可查出已软删的记录,但注意:它返回的是“当前软删态”的模型,deleted_at已有值,不是删除动作发生前的状态 - 真要还原删除前一刻的数据,得依赖数据库层面的 binlog、触发器存档表,或在
deleting事件里提前保存 —— AR 本身不保留历史快照 - 若只是想恢复软删记录,应走
onlyTrashed()+restore()路径:User::find()->onlyTrashed()->where(['id' => 123])->one()?->restore()
真正难的不是“怎么取”,而是“取哪些字段才够用”。业务日志、权限校验、异步任务回滚,往往需要比 toArray() 更精确的原始值,这时候别偷懒,老老实实调 getOldAttributes() 或手动指定字段读取。











