ThinkPHP 8.0 多字段模糊搜索需明确四要点:字段组合用竖线|实现OR逻辑、关键词手动转义%_防误匹配、空值动态过滤避免无效条件、复杂场景封装搜索器;且OR模糊查询无法走前缀索引,大数据量须对接全文索引或Elasticsearch。

ThinkPHP 8.0 实现多字段模糊搜索,核心不是堆条件,而是分清「字段组合方式」「空值处理」「通配符安全」和「性能边界」四件事。直接写 where(['title|content' => ['like', '%关键词%']]) 看似简单,但漏掉任意一环,轻则查不到数据,重则 SQL 注入或全表扫描。
多字段 OR 模糊匹配:用竖线 | 而不是数组拼接
想在 title、content、username 三个字段中任一字段包含关键词,必须用字段名之间加 |,且整个字段键写成字符串:
-
正确写法:
->where('title|content|username', 'like', '%' . $keyword . '%') -
错误写法:
->where(['title' => ['like', '%k%'], 'content' => ['like', '%k%']])—— 这是 AND 关系,逻辑不符 - 字段名之间不能有空格,
'title | content'会解析失败;大小写需与数据库列名严格一致 - 若字段类型不一致(如 TEXT 和 VARCHAR),建议统一指定字符集:
->bind(['title|content|username' => PDO::PARAM_STR])
关键词含特殊字符:手动转义 % 和 _
用户搜 “a_b” 或 “100%”,不转义就会被当成通配符,导致误匹配或语法错误:
- 用
addcslashes($keyword, '%_')预处理,再拼百分号:$escaped = addcslashes($keyword, '%_'); - 然后构造:
->where('title|content', 'like', '%' . $escaped . '%') - 无需额外设 ESCAPE 符——ThinkPHP 底层执行时已自动处理转义后的字符,不会触发 SQL 的 ESCAPE 子句
- 注意:
htmlspecialchars()或strip_tags()对模糊搜索无效,它们不处理 SQL 通配符
空值与无效参数:动态构建 where 条件
搜索表单常带空字段(如状态未选、时间未填),直接塞进 where 数组会导致 WHERE status = '' 这类错误条件:
- 先过滤掉空值:
$filter = array_filter($request, function($v) { return $v !== '' && $v !== null && $v !== [] && !is_string($v) || strlen($v) > 0; }, ARRAY_FILTER_USE_BOTH); - 对模糊字段单独处理,不混入主数组:
if (!empty($keyword)) { $query->where('title|content', 'like', '%' . addcslashes($keyword, '%_') . '%'); } - 对范围类字段(如时间区间)用
whereBetween(),对单选状态用where('status', $status),全部走链式调用,不依赖数组合并
复杂组合搜索:用搜索器(Searcher)而非硬编码
当需求升级为「标题含关键词 + 创建时间在某区间 + 状态为启用」,建议封装为搜索器,而不是在控制器里拼一堆 where:
- 在模型中定义方法:
public function searchKeywordAttr($query, $value) { if ($value) { $escaped = addcslashes($value, '%_'); $query(function ($builder) use ($escaped) { $builder->where('title|content|username', 'like', '%' . $escaped . '%'); }); } } - 调用时:
UserModel::withSearch(['keyword', 'createTime'], ['keyword' => $kw, 'createTime' => $range])->select(); - 搜索器内
$query是闭包,只能通过$query(function ($builder) { ... })方式注入条件,不能直接调$query->where() - 多个搜索器并行时,外部写的
where()会先执行,搜索器后追加,避免冲突的关键是:搜索器内部不做覆盖,只做补充
不复杂但容易忽略:多字段模糊本质是 OR 查询,它天然无法走索引前缀,大数据量时务必配合全文索引(MySQL FULLTEXT)或 Elasticsearch 做兜底。TP8.0 本身不提供搜索引擎集成,这块得自己桥接。


















