全局作用域是Laravel中为Eloquent模型自动添加查询约束的机制,通过实现Scope接口并在apply方法中定义条件,如status=1;在模型的boot方法中使用addGlobalScope注册后,所有查询包括get、first和关联查询都会自动应用该限制,无需手动调用;可通过withoutGlobalScope或withoutGlobalScopes临时移除特定或全部全局作用域,适用于租户隔离、多语言支持等场景。

在 Laravel 中,全局作用域(Global Scopes)是一种为 Eloquent 模型自动添加约束条件的机制。它可以在不修改查询代码的前提下,确保每次查询该模型时都应用特定的过滤条件,比如软删除、租户隔离或多语言支持等场景。
什么是全局作用域?
全局作用域会自动应用到模型的所有查询中,包括关联查询和简单的 get()、first() 等操作。与局部作用域(Local Scopes)不同,全局作用域不需要手动调用,是“隐形”的限制。
如何定义全局作用域?
实现全局作用域需要创建一个类,实现 Illuminate\Database\Eloquent\Scope 接口,并重写 apply 方法。
示例:为用户模型添加“未被删除”的默认约束
假设我们有一个 User 模型,希望所有查询默认只返回状态为激活的用户(status = 1)。
// 创建 Scope 类 app/Scopes/ActiveScope.php
```php
namespace App\Scopes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
class ActiveScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
$builder->where('status', 1);
}
}
```
// 在 User 模型中注册全局作用域
```php
namespace App\Models;
use App\Scopes\ActiveScope;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
protected static function boot()
{
parent::boot();
static::addGlobalScope(new ActiveScope);
}
}
```
现在,任何对 User::get() 或 User::find(1) 的调用都会自动加上 where status = 1 的条件。
移除全局作用域
有时候你希望临时绕过全局作用域,可以使用 withoutGlobalScope() 方法。
```php
// 获取所有用户,包括非激活的
$users = User::withoutGlobalScope(ActiveScope::class)->get();
```
也可以移除所有全局作用域:
```php
$users = User::withoutGlobalScopes()->get();
```
如果只想移除某个字段相关的约束(如通过匿名函数定义的作用域),也可以传入对应的类名或闭包引用。
使用匿名全局作用域
Laravel 也支持直接在模型中使用闭包定义全局作用域,适用于简单逻辑。
```php
protected static function boot()
{
parent::boot();
static::addGlobalScope('active', function (Builder $builder) {
$builder->where('status', 1);
});
}
```
这种方式更简洁,但不利于复用。推荐复杂逻辑使用独立的 Scope 类。
实际应用场景
- 多租户系统:自动添加 tenant_id 条件,保证数据隔离。
- 软删除扩展:除了 Laravel 自带的 soft deletes,还可加更多状态过滤。
- 多语言内容:根据当前语言环境自动筛选翻译字段。
- 启用状态控制:如仅显示 is_active = true 的记录。
基本上就这些。只要理解了 addGlobalScope 和 withoutGlobalScope 的用法,就能灵活控制模型的数据访问边界。注意避免滥用,否则可能让查询行为变得难以追踪。










