thinkphp 8 中模型不再继承 query,find()、select() 等查询方法须通过模型实例->where()->find() 或 usermodel::query()->where()->find() 调用;save() 不再智能识别更新,update() 必须带 where 条件;软删除需显式定义 $deletetime,否则失效。

ThinkPHP 8 中模型查询方法没有“重命名”这回事——你看到的 find()、select() 报错或行为异常,大概率是方法被移除、签名变更,或是调用上下文不匹配,不是名字改了就能解决的。
TP8 模型类不再继承 Query,find() 等方法必须显式调用
TP8 彻底剥离了模型类对 think\Query 的继承,think\Model 现在只负责数据映射和生命周期管理。所有查询能力都收归 think\db\Query 实例,模型本身不再直接提供 find()、select()、where() 等链式方法。
- 错误写法:
UserModel::where('id', 1)->find()—— TP8 下会报Call to undefined method - 正确写法:先获取查询对象,再操作:
(new UserModel())->where('id', 1)->find()或更推荐的静态入口:UserModel::query()->where('id', 1)->find() -
UserModel::find(1)仍可用,但这是静态快捷方式,本质仍是调用query()->find(1),不能混用链式条件(如UserModel::find(1)->where(...)无效)
save() 和 update() 行为差异变大,别无脑替换
TP8 中 save() 不再自动识别主键更新,也不再默认走 INSERT ... ON DUPLICATE KEY UPDATE;update() 则明确要求必须带 where 条件,否则抛出异常。
-
$user->save():仅当模型已赋值主键(如$user->id = 5)且数据存在时才执行 UPDATE;否则一律 INSERT —— 不再尝试根据主键是否存在智能切换 -
UserModel::update($data):必须搭配where,例如UserModel::update($data, ['id' => 5]),否则直接报错Missing WHERE condition - 旧代码里把
save()当成“万能更新”用的,升级后容易漏掉主键赋值,导致静默插入重复记录
软删除字段名和配置必须显式声明,否则 deleteTime 失效
TP8 要求软删除字段(如 delete_time)必须在模型中通过 $deleteTime 属性明确定义,且类型需与数据库一致;不再接受全局配置或约定推导。
- 必须写:
protected $deleteTime = 'delete_time';(字符串字段)或protected $deleteTime = ['delete_time', 'datetime'];(时间戳自动转换) - 若数据库字段是
is_deleted布尔型,得配成:protected $deleteTime = 'is_deleted'; protected $defaultSoftDelete = 0; - 没声明
$deleteTime,调用delete(true)会变成硬删,且withTrashed()、onlyTrashed()全部失效 - TP5/6 中靠
soft_delete配置开启的写法,在 TP8 中完全不生效
最常被忽略的是模型实例化方式和查询入口的割裂——很多人还在沿用 TP6 的“模型即查询器”直觉,结果在 TP8 里写了一堆 where 却发现根本没进 SQL。动手前先确认你调用的是模型类静态方法,还是模型实例 + query(),二者路径不同,容错率也不同。











