当条件逻辑仅依赖单一请求参数是否存在/非空且彼此独立时,应优先使用 when;它比嵌套 if 更简洁、可读性强、不易出错,并天然规避作用域与重复赋值问题。

直接用 when 方法最稳妥,比一堆 if 更简洁、可读性更强,也更少出错。
什么时候该用 when 而不是 if
当条件逻辑只依赖「某个请求参数是否存在/非空」,且每个条件彼此独立时,when 就是首选。它天然规避了变量作用域、重复赋值、漏写 $query-> 前缀等问题。
-
when(request('name'), fn ($q, $v) => $q->where('name', 'like', "%{$v}%")):只要request('name')不为null、''、[]或0(注意:'0'是字符串,会被视为真),就执行闭包 - 如果字段允许值为
'0'(比如状态码、开关标识),就得显式判断:when(!is_null(request('status')), fn ($q, $v) => $q->where('status', $v)) - 不要把多个字段塞进一个
when闭包里做合并判断,比如when($request->all(['a','b']), ...)—— 这会让逻辑变重、难调试、无法单独开关某一项
filled() 和 has() 到底怎么选
绝大多数表单筛选场景下,用 $request->filled('field') 更安全。它严格排除 null、''、[]、0(整数零),只对真正有意义的输入生效。
-
$request->has('field')只检查键是否存在,哪怕值是空字符串或0也会返回true,容易误触发条件 - 布尔型开关(如
?active=1或?archived=0)才适合用has(),因为你要的是「用户明确传了这个参数」,而不是「参数有业务意义」 - 在
when里混用两者没问题,但别在同一个字段上交替使用,否则行为不一致
关联表字段搜索必须拆开写
多表联合筛选时,主表条件和关联表条件不能混在 whereHas 闭包里。MySQL 执行时会把闭包内所有 where 都当成关联模型的约束,主表字段查不到就会静默失败。
- 错误写法:
->whereHas('orders', function ($q) { $q->where('status', 'done')->where('users.name', 'like', '%张%'); })——users.name在orders表里根本不存在 - 正确拆分:
->where('name', 'like', '%张%')->whereHas('orders', fn ($q) => $q->where('status', 'done')) - 如果要模糊搜关联字段(比如订单备注),只能放在
whereHas闭包里:->whereHas('orders', fn ($q) => $q->where('remark', 'like', "%{$request->remark}%"))
复杂点在于:当动态条件涉及多个关联关系、又带排序或分页时,when 虽然语法干净,但底层仍生成 JOIN,容易因笛卡尔积拖慢查询——这时候得回头检查是否真需要实时 JOIN,还是该拆成两次查询或加缓存。











