_basescope 是 thinkphp 模型中定义的静态数组属性,仅在调用 scope() 或显式启用作用域时合并进当前模型的 select()、find() 等查询,不作用于 db::name()、关联查询、子查询及 save()/update(),且不被 withoutglobalscope() 影响。

全局查询范围 _baseScope 是什么,它到底在哪生效
ThinkPHP 的 _baseScope 不是“自动加载的全局过滤器”,而是一个模型类里可定义的静态属性,仅在该模型调用 scope() 或显式启用作用域时才被合并进查询条件。它不会影响 Db::name()、Model::withoutGlobalScope() 以外的任意查询,也不会穿透到关联模型或子查询中。
常见错误现象:_baseScope 写了但没生效,或者误以为它能替代软删除中间件;还有人把它当成 Laravel 风格的全局 scope,结果发现 where() 直接调用完全绕过它。
-
_baseScope必须是数组,键为字段名,值为条件值(支持['>', 0]等表达式) - 只对当前模型的
select()、find()、count()等主动查询方法起作用,不干预save()或update() - 若模型继承自
think\Model且未重写scope(),则框架会默认读取该属性并合并进查询;但一旦你自定义了scope()方法,就必须手动调用array_merge($this->_baseScope ?? [], $scope)
如何让 _baseScope 和软删除、租户隔离等条件互不干扰
多个全局条件混用时,_baseScope 容易和 SoftDelete 行为、多租户 tenant_id 过滤产生冲突——比如软删除字段被覆盖,或租户条件被漏掉。根本原因是它们都依赖“查询前自动注入条件”,但 ThinkPHP 没有统一的 global scope 注册机制。
使用场景:SaaS 系统中,用户模型既要排除已删除记录,又要限定当前租户数据,还可能加状态过滤。
- 不要把租户 ID 写进
_baseScope,改用中间件 +Db::listen()动态绑定,避免命令行或队列任务误带租户上下文 - 软删除建议仍走
SoftDelete行为,它内部通过baseQuery钩子注入,优先级高于_baseScope,不会被覆盖 - 若必须共存,把
_baseScope改成方法getBaseScopeAttr(),并在其中判断当前是否处于租户上下文(如检查app('tenant.id')是否存在),动态返回不同数组
withoutGlobalScope() 为什么有时失效,怎么真正跳过 _baseScope
调用 withoutGlobalScope() 后 _baseScope 依然生效,是因为这个方法只处理通过 use \think\model\concern\SoftDelete; 等行为注册的 scope,而 _baseScope 是模型原生机制,不走同一套注册流程。
性能影响:每次查询都合并 _baseScope 是轻量操作,但若里面包含子查询或闭包(非法但有人试过),会导致 SQL 构建失败或 N+1。
- 要彻底跳过
_baseScope,只能临时重置:(new User())->setBaseScope([])->select() - 更稳妥的做法是定义一个空作用域,比如
public function scopeRaw($query) {},然后用User::scope('raw')->select(),因为scope()调用时会清空默认合并逻辑 - 注意:
withoutGlobalScope()对Db::name('user')根本无效——它只作用于模型实例,不是查询构造器
为什么别在基类模型里统一写 _baseScope = ['status' => 1]
看似省事,实则埋雷。不同子模型对 status 字段语义完全不同:用户表是“启用/禁用”,订单表是“待支付/已完成”,商品表可能是“上架/下架”。硬编码会导致查询错乱,而且无法被子类干净覆盖——PHP 不支持静态属性继承覆盖。
兼容性影响:ThinkPHP 6.0+ 中,_baseScope 已非文档主推方式,官方倾向用 scope 方法 + protected $scope = ['common' => 'commonScope'] 配置,更可控。
- 基类中留空
_baseScope,或设为null,强制子类显式声明 - 若真需统一状态字段,用 trait 封装一个
activeScope()方法,再在各模型里scope('active')显式调用 - 调试时直接
dump((new User())->getBaseScope()),比翻基类代码更快定位来源
最常被忽略的是:_baseScope 在模型的静态上下文中解析,所以不能访问 $this->app 或依赖容器实例——任何需要运行时判断的条件,都得绕道 scope 方法或查询监听器。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










