最直接的方法是开启查询日志验证全局作用域是否生效:调用db::enablequerylog(),执行user::first()等查询,再用db::getquerylog()检查sql是否含预期where条件,并对比withtrashed()、withoutglobalscopes()等调用的sql差异;同时确认作用域在boot()中注册成功,避免闭包注册导致无法精准排除。

最直接的方法是开启查询日志,观察生成的 SQL 是否自动包含了全局作用域添加的条件。全局作用域不是“写完就生效”的黑盒,它会在查询构建阶段悄悄注入 where 子句——只有看到真实 SQL,才能确认它是否起效、是否叠加、是否冲突。
开启查询日志并执行简单查询
在开发环境(如 Tinker 或控制器中)临时启用查询日志:
- 调用 DB::enableQueryLog() 开启记录
- 执行一句基础查询,比如 User::first() 或 Post::count()
- 用 DB::getQueryLog() 获取最后一条或全部日志,检查 SQL 字符串
如果模型注册了 ActiveScope(加 where status = 'active'),你将看到类似:
对比 withTrashed() 或 withoutGlobalScopes() 的 SQL 差异
软删除(SoftDeletes)本身就是一个全局作用域。通过对比可快速验证作用域是否被正确包裹:
-
User::first() → 带
where deleted_at is null - User::withTrashed()->first() → 不带该条件(Laravel 内置绕过逻辑)
-
User::withoutGlobalScopes()->first() → 既没
deleted_at,也没你自定义的status条件 -
User::withoutGlobalScope(ActiveScope::class)->first() → 有
deleted_at is null,但无status条件
每种调用生成的 SQL 差异,就是全局作用域生效范围和嵌套顺序的直观证据。
检查作用域注册是否真正完成
光看 SQL 不够,还得确认作用域有没有被成功挂载。常见失效原因是注册位置错误:
- 必须在模型的 boot() 或 booted() 静态方法中调用
addGlobalScope() - 不能放在构造函数、静态属性初始化、或某个辅助方法里
- 若用了多个作用域,后注册的会“包住”先注册的(洋葱模型),例如租户作用域在外层、状态作用域在内层
可在 boot() 里加一行 Log::debug('ActiveScope registered'),然后运行一次查询,看日志是否输出——这是判断注册逻辑是否被执行的最快方式。
注意闭包作用域无法按需排除
如果用闭包方式注册:static::addGlobalScope('active', function ($b) { $b->where('status', 'active'); });
- 它能生效,但只能靠 withoutGlobalScope('active') 排除
- 如果漏写键名(如只传
function () {...}),Laravel 会生成随机 ID,你将无法针对性关闭 - 类方式更稳妥:
new ActiveScope()可直接用withoutGlobalScope(ActiveScope::class)
这种限制直接影响调试:你想临时查所有用户(含非 active),却因闭包无名而只能清空全部作用域,反而掩盖了其他问题。











