全局作用域是Laravel中为模型所有查询自动添加约束的机制,如ActiveUserScope会自动过滤status为active的用户,通过implementing Scope接口并重写apply方法实现,在模型booted中注册后生效,可用withoutGlobalScope临时移除,适用于软删除、多租户等场景,但需避免复杂逻辑以防性能问题。

在 Laravel 的 Eloquent 模型中,全局作用域(Global Scopes)是一种为模型的所有查询自动添加约束条件的机制。它非常适合用于实现软删除、多租户系统、状态过滤等通用需求,而无需每次手动添加相同条件。
什么是全局作用域
全局作用泩会在模型的每一次数据库查询中自动应用,包括 where、get、first、paginate 等方法,除非你显式地移除它。
Laravel 自带的 SoftDeletes 就是通过全局作用域实现的:自动排除被“软删除”的记录。
如何定义并使用全局作用域
创建一个全局作用域需要实现 Illuminate\Database\Eloquent\Scope 接口,并定义 apply 方法。
示例:为用户模型添加“仅启用用户”作用域
第一步:创建 Scope 类
php artisan make:scope ActiveUserScope
生成的类如下:
namespace App\Scopes;use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Scope;
class ActiveUserScope implements Scope { public function apply(Builder $builder, Model $model) { $builder->where('status', 'active'); } }
第二步:在模型中注册全局作用域
namespace App\Models;use App\Scopes\ActiveUserScope; use Illuminate\Database\Eloquent\Model;
class User extends Model { protected static function booted() { static::addGlobalScope(new ActiveUserScope); } }
现在,所有对 User 模型的查询都会自动加上 status = 'active' 条件。
例如:
User::all(); // SELECT * FROM users WHERE status = 'active';
临时移除全局作用域
有时你需要获取包含非活跃用户的数据,可以使用 withoutGlobalScope 方法:
// 获取所有用户(包括非活跃) User::withoutGlobalScope(ActiveUserScope::class)->get();// 移除所有全局作用域 User::withoutGlobalScopes()->get();
// 移除特定几个作用域 User::withoutGlobalScopes([ ActiveUserScope::class, AnotherScope::class ])->get();
匿名全局作用域(一次性使用)
如果某个作用域只在特定模型中使用一次,可以直接在模型中用闭包定义:
protected static function booted()
{
static::addGlobalScope('active', function (Builder $builder) {
$builder->where('status', 'active');
});
}
移除时使用作用域名称:
User::withoutGlobalScope('active')->get();
注意事项与最佳实践
- 全局作用域会影响 withTrashed() 和 onlyTrashed() 之外的软删除行为,注意避免冲突。
- 避免在全局作用域中加入复杂逻辑或性能消耗大的子查询。
- 命名清晰,便于维护和调试。
- 多租户系统中常用于自动添加 tenant_id 条件。
基本上就这些。合理使用全局作用域能大幅减少重复代码,提升数据安全性与一致性。但也要注意别滥用,避免让查询行为变得“隐式”而难以追踪。










