ThinkPHP 不提供开箱即用的搜索接口,需手动实现:接收关键词(GET/POST)、非空校验、安全过滤、构造 where 数组或链式查询(支持 like 和 or 组合),并注意 withSearch 需显式调用且方法命名严格匹配 searchXxxAttr 规范。

ThinkPHP 本身不提供开箱即用的「搜索接口」,所谓搜索接口,就是接收关键词、构造查询、返回结构化数据的 HTTP 接口;它本质是 GET 或 POST 请求 + 数据库查询 + JSON 响应,不是某个 magic 方法能一键生成的。
怎么写一个基础搜索接口(GET + where 数组)
最常用的是用 Request::get('keywords') 拿参数,再拼 where 条件查数据库。但直接塞进数组会出问题——空值也会参与查询,导致结果为空。
- 必须先判断关键词是否非空:
if (!empty($keywords)) { $map[] = ['title', 'like', "%{$keywords}%"]; } -
where数组只支持等值匹配(=),模糊查必须显式写成三元形式,不能写成['title' => "%{$keywords}%"] - 多个字段都要匹配同一关键词时,得用
where链式调用 +or组合:->where('title', 'like', "%{$keywords}%")->whereOr('content', 'like', "%{$keywords}%") - 记得对关键词做
trim()和 SQL 特殊字符过滤,否则可能被注入或查不出数据
为什么 withSearch 搜索器没生效
搜索器不是自动触发的,它需要模型里有对应方法、控制器里显式调用 withSearch,且字段名和方法名要严格对应。
- 模型中方法名必须是
searchXxxAttr(Xxx是驼峰字段名,如create_time对应createTime),后缀Attr缺一不可 - 调用时不能只写
->withSearch(['createTime']),必须传第二个参数:->withSearch(['createTime'], $params),否则搜索器收不到值 -
$query参数是闭包,不是Query对象,不能直接$query->where(),得用$query($builder)方式修改查询构造器 - 多个搜索器同时启用时,它们的执行顺序在普通
where之后,所以外部写的where('status', 1)不会被搜索器覆盖,但也不能指望它被修正
什么时候该换 Elasticsearch 而不是硬扛 LIKE
当出现 SELECT ... WHERE title LIKE '%关键词%' 查询变慢、用户抱怨搜不准、或需要拼音/错别字/高亮时,说明 MySQL 的 LIKE 已经撑不住了。
立即学习“PHP免费学习笔记(深入)”;
- 单表几万条以内、字段少、关键词固定,用
where+LIKE完全够用;别一上来就上 ES,徒增运维复杂度 - ES 要求数据同步:你改了数据库,得同步更新 ES 索引,要么监听事件、要么加钩子,漏一条就会搜不到
- TP6 集成 ES 通常走
elasticsearch/elasticsearch官方客户端,不是靠模型搜索器;withSearch只负责构造 SQL,不碰 ES 请求 - 如果只是想支持中文分词,先试试
jieba-php在 PHP 层切词,再拿词组去WHERE title LIKE ? OR title LIKE ?,比直接上 ES 轻量得多
真正卡住人的从来不是「怎么写个搜索接口」,而是没想清楚:这个搜索到底要解决什么问题?是用户输错字要容错,还是数据量大到 LIKE 查不动,又或者字段太多要跨字段组合筛选——不同目标,技术选型和实现重心完全不同。



















