thinkphp数据筛选接口应优先使用where()链式调用或二维数组组装条件,配合select()或paginate()返回结果;避免php层array_filter(),禁用未校验的$_get转map,注意空值、like大小写、时区及分页count。

ThinkPHP 实现数据筛选接口,核心就一条:用好 where() 链式调用或二维数组条件组装,配合 select() 或分页方法返回结果。别在控制器里手动 array_filter() 原始数据集——那是数据库该干的活,不是 PHP 层该补的漏。
where() 链式调用适合简单动态条件
当筛选字段固定、逻辑清晰(比如搜索框+状态下拉+时间范围),链式写法最直观,也最容易调试。
-
where()支持三参数形式:where('field', 'operator', 'value'),如where('status', '=', 1);省略 operator 默认为= - 模糊查询必须用
whereLike()或where('name', 'like', '%'.$kw.'%'),直接where('name', '%'.$kw.'%')是全等匹配,不会生效 - 多个
where()调用默认是 AND 关系;要用 OR,得套whereOr()或闭包:where(function ($query) { $query->where('a', 1)->whereOr('b', 2); }) - 注意空值陷阱:用户没输关键词时,
$kw = $this->request->param('kw', ''),如果直接拼'%'.$kw.'%'会变成%%,MySQL 可能全表扫——加个if (!empty($kw)) { $query->whereLike('name', '%'.$kw.'%'); }更安全
二维数组条件适合复杂组合与权限过滤
当条件来自前端 JSON、需支持“字段名/操作符/值”自由组合,或者要统一注入租户 ID、软删除字段等隐式条件,二维数组方式更可控。
- 格式是
[['field', 'operator', 'value'], ...],例如:[['status', '=', 1], ['created_at', '>=', '2025-01-01'], ['title', 'like', '%bug%']] - 数组可动态 push,方便循环组装:
if ($uid) $map[] = ['user_id', '=', $uid]; - 注意
like操作符必须小写,大写LIKE会被当成字段名处理,报错Unknown column 'LIKE' in 'where clause' - 不建议把整个
$_GET直接转成 map 使用——缺乏字段白名单校验,容易被注入非预期字段(如password、is_admin)
时间范围筛选别只靠字符串拼接
用 whereTime() 而不是手拼 where('create_time', '>=', $start.' 00:00:00'),它自动处理时区、日期格式兼容性和 SQL 安全转义。
-
whereTime('create_time', 'between', [$start, $end])—— 生成BETWEEN '2025-01-01 00:00:00' AND '2025-01-31 23:59:59' -
whereTime('update_time', 'today')、whereTime('create_time', 'week')等快捷值也支持 - 若传入的时间字符串格式不标准(如
2025/01/01),whereTime()可能解析失败,建议前端统一传Y-m-d或Y-m-d H:i:s - 跨天查询注意时区:配置
default_timezone后,whereTime()才会按项目时区生成时间边界,否则可能少查或重查 1 小时
分页 + 筛选接口必须带 count 查询
别只写 select() 返回数据,忘了用 count() 统计总数——否则前端分页器无法算总页数,用户体验直接崩。
- 正确姿势是先 clone 查询对象:
$countQuery = clone $query; $total = $countQuery->count();,再执行$list = $query->page($page, $limit)->select(); - 用
paginate()更省事:$list = $query->paginate(['page' => $page, 'list_rows' => $limit]);,它内部自动做 count 和 limit - 但注意:含
group或复杂子查询时,paginate()的 count 可能不准,此时必须手写count(1)或count(DISTINCT id)并显式指定 - 返回结构别硬编码:
return json(['list' => $list, 'total' => $total, 'page' => $page]);,字段名保持前后端约定一致,避免每次改接口都得同步文档
真正难的不是写对 where 条件,而是判断哪些条件该进 SQL,哪些该在 PHP 层后过滤——比如「用户可见性」这类业务规则,常混着权限、组织架构、状态机,硬塞进 where 容易失控。这时候更适合拆成「主查询 + 后置过滤」两段逻辑,比堆一堆 or 和子查询更可读、可测、可维护。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











