ThinkPHP 6.x 已移除全局作用域,改用需显式调用的查询范围(scope)或模型静态 baseQuery 方法实现默认条件;scope 不自动生效、不作用于关联查询,baseQuery 则影响所有静态查询。

全局作用域在 ThinkPHP 6.x 中已移除,别再找 globalScope
ThinkPHP 6.0 起彻底删除了模型的 globalScope 属性和相关机制。如果你在文档或老项目里看到这个写法,它在当前版本会直接报错或静默失效。官方改用「查询范围(Query Scope)」替代,但注意:它不是自动生效的“全局”,必须显式调用。
用 scope 方法定义可复用的查询条件
在模型中定义一个公共方法,以 scope 开头,参数为 $query(think\db\Query 实例),内部链式调用 where、order 等即可:
class User extends Model
{
public function scopeActive($query)
{
$query->where('status', 1)->where('delete_time', null);
}
}
调用时需显式使用:User::scope('active')->select() 或简写为 User::active()->select()。不调用就不会生效——这点和旧版“全局”语义完全不同。
- 多个范围可连用:
User::active()->recent()->select() - 范围方法支持传参,例如
scopeType($query, $type),调用时写User::type('admin') - 范围只影响当前查询,不会污染其他操作(比如
save()不受其影响)
想“默认加 where”?用模型的 baseQuery 静态方法更稳妥
如果真需要所有查询(包括 find、select、关联预载入)都自动带上某个条件,不要硬套 scope,而是重写模型的 baseQuery 方法:
立即学习“PHP免费学习笔记(深入)”;
class User extends Model
{
protected static function baseQuery()
{
return (new Query())->where('delete_time', null);
}
}
该方法返回的 Query 实例会被所有静态查询方法(get、all、find 等)自动合并。但注意:
- 它对动态实例方法(如
$user->together())无效 - 关联查询中若未指定
query参数,也不会自动继承 - 如果用了软删除,建议直接启用
use SoftDeletetrait,它内部就基于baseQuery实现,比手写更可靠
常见踩坑点:scope 不生效、条件被覆盖、关联查询漏掉
最常遇到的问题不是写不对,而是没意识到 scope 的调用时机和作用边界:
-
User::where('id', 1)->active()->find():条件顺序错误,where在前会导致scope的where被忽略(ThinkPHP 的 where 合并逻辑是后写覆盖同字段) -
User::with('profile')->select():关联模型Profile不会自动应用User的 scope,得单独给Profile定义并调用自己的 scope - 在控制器里写
User::withoutGlobalScope()->select():TP6 已无此方法,删掉;如需临时绕过 baseQuery,只能手动 new Query() 构造 - scope 方法里用了
$this->field或访问模型属性:错,$query是静态上下文,没有$this指向实例
真正要实现“默认条件”的地方,往往不是 scope,而是 baseQuery 或软删除机制——很多人卡在这一步,是因为还在按 TP5 的思路找“全局作用域”。



















