使用 withouttrashed() 方法可以过滤掉被软删除的数据,确保 find() 只返回未被标记为删除的记录。在 thinkphp8 中,只需在查询构建器链式调用该方法即可,它会向 sql 语句追加 where_null('delete_time') 条件(假设默认字段名为 delete_time)。

find() 默认行为与软删除冲突
当模型启用了软删除特性时,直接调用 find() 会受全局作用域影响,自动排除已删除数据。如果业务逻辑需要获取所有记录(包括已删除的),或者需要明确区分状态,这种默认行为可能导致数据遗漏或误判。例如,管理员后台可能需要查看回收站内容,此时默认的 find() 无法返回目标数据。

$user = User::find(1);
// 如果 ID 为 1 的用户已被软删除,$user 将为 null
// 即使数据库中该记录存在,也会被 where_null('delete_time') 过滤
上述代码展示了默认行为。若用户 1 已被软删除,find() 返回 null。要解决此问题并显式控制是否包含软删除数据,需结合 withoutTrashed() 或 withTrashed()。但在本题语境下,重点在于如何用 withoutTrashed() 确保“查出”的是有效数据,即防止因意外状态导致查不到数据,或在混合查询中明确排除已删除项。
立即学习“PHP免费学习笔记(深入)”;
修复 Core bailout 状态损坏安全问题,以及 BZ2、DOM、PDO、Opcache/JIT 内存与执行错误,改进 Unicode 字素处理、URL 解析、TLS 流状态、信号分发及会话错误处理。
withoutTrashed() 的具体用法与效果
withoutTrashed() 的作用是移除可能存在的“包含软删除数据”的作用域,并强制添加“仅查询未删除数据”的条件。它与 find() 连用时,语义上更加明确,尤其在复杂查询或继承关系中,能避免父类或全局作用域带来的歧义。其实际效果等同于手动添加 whereNull('delete_time')。

$user = User::withoutTrashed()->find(1); // 无论全局作用域如何设置,此查询强制只查找 delete_time 为 NULL 的记录 // 若 ID 1 已被删除,返回 null;若未删除,返回完整对象
对比直接使用 find(),withoutTrashed()->find() 在代码意图上更清晰,表明开发者明确希望忽略软删除记录。这在审计日志、数据恢复预览等场景中非常有用,确保操作的对象是“活”数据。若需获取已删除数据,则应使用 withTrashed()->find()。
基于 delete_time 字段值的判断结果
在实际运行中,withoutTrashed() 的效果取决于模型配置的软删除字段值。ThinkPHP8 默认使用 delete_time 字段,且认为该字段为 null 表示未删除,非空表示已删除。若数据库 schema 修改了该字段名或逻辑,需通过 setDeleteTimeField() 调整。此外,若 delete_time 存储的是字符串而非时间戳,比较逻辑可能失效,需确保类型一致。


















