thinkphp模型作用域是封装业务筛选逻辑的标准方式,以scope开头命名、接收$query和参数并返回$query,支持链式调用与组合复用;全局作用域可自动添加默认条件,动态方法则灵活性不足。

ThinkPHP模型作用域(Scope)是把业务筛选逻辑从控制器抽离、封装进模型的标准化方式,它不执行查询,只修饰查询对象,天然支持链式调用和组合复用——这才是简化复杂条件查询的核心机制。
作用域怎么写才真正可用
必须以 scope 开头命名方法,只接收两个参数:$query(查询对象)和一个额外参数(如字符串、数组),且必须返回 $query,否则链式中断。
- 正确示例:
public function scopeActive($query) { return $query->where('status', 1); } - 错误写法:漏掉
return,或写了return $query->select()这类终结操作 - 带参写法:
public function scopeSearch($query, $params) { if (!empty($params['keyword'])) { $query->where('name', 'like', "%{$params['keyword']}%"); } return $query; }
多条件组合不再堆 if 判断
前端传来「状态」「关键词」「时间范围」三个筛选项,控制器里不用写三层 if 套 where,只需统一传参、一次调用:
- 定义好作用域后,控制器代码可精简为:
User::active()->search(['keyword' => $kw, 'start' => $start])->latest()->paginate(); - 每个作用域专注一件事:active 管状态、search 管模糊+时间、latest 管排序,职责清晰、互不干扰
- 后续加新条件(比如按标签筛选),只需新增
scopeByTag,控制器调用链直接追加->byTag($tag)
全局作用域自动过滤软删除或权限字段
对所有查询默认加上“未删除”或“可见状态”,避免每次手动写 where('delete_time', null) 或 where('status', 1):
- 在模型
boot()中注册:static::addGlobalScope('notDeleted', function ($query) { $query->where('delete_time', null); }); - 需要临时绕过时,用
User::withoutGlobalScope('notDeleted')->select() - 注意:全局作用域不会自动兼容软删除行为,
useSoftDelete需单独配置或显式加条件
作用域比动态方法更灵活可控
动态方法(如 whereName)依赖字段映射、只能处理单字段等值匹配;而作用域能封装任意复杂逻辑:
- 支持
whereTime、whereLike、whereHas、闭包子查询等全部查询能力 - 可做空值兜底:
if (!empty($params['start'])) { $query->whereTime('create_time', '>=', $params['start']); } - 可组合关联条件:
public function scopeWithOrders($query) { return $query->with(['orders' => function ($q) { $q->where('status', 'paid'); }]); }
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











