必须把%拼到php变量里再绑定,不能写在sql字符串中;否则pdo将'%?%'视为字面量字符串而非通配符模式,导致查询失败或返回空结果。

必须把 % 拼到 PHP 变量里再绑定,不能写在 SQL 字符串中——否则 PDO 会把它当字面量处理,查不到数据,还可能报错。
为什么 "WHERE name LIKE '%?%'" 是错的
PDO 占位符只替换值,不参与 SQL 解析。写成 "'%?%'" 后,PDO 实际传入的是带单引号的字符串,比如 '%admin%',整个被当成一个固定字符串字面量,而不是带通配符的模式。数据库执行的是 WHERE name LIKE '%admin%' 还是 WHERE name LIKE '''%admin%''',取决于驱动实现,但结果几乎总是查不到。
常见错误现象:
- 查询返回空数组,哪怕数据库里明明有匹配记录
- 用
echo $pdo->lastInsertId()或EXPLAIN看执行计划,发现key为NULL - 错误提示
SQLSTATE[HY093]: Invalid parameter number
PDO::prepare() 中 LIKE 的正确参数绑定方式
通配符必须由 PHP 拼接进绑定值,SQL 语句里只留干净的占位符。
正确示例:
$keyword = $_GET['q'] ?? '';
$keyword = trim($keyword);
if ($keyword === '') {
// 建议跳过查询,避免 LIKE '%%' 全表扫
$results = [];
} else {
$stmt = $pdo->prepare("SELECT * FROM users WHERE name LIKE ?");
$stmt->execute(['%' . $keyword . '%']); // ✅ % 在 PHP 层加
$results = $stmt->fetchAll();
}
关键点:
- 用
?或命名占位符(如:term),但 SQL 中不要出现% - 绑定值是完整字符串,如
'%张%'、'张%'(前缀)、'%张'(后缀) - 对输入做
trim(),防止前后空格干扰匹配或触发全表扫描 - 若需多字段 OR 匹配(如 title 或 description 含关键词),得写两个 LIKE 条件,不能靠一个占位符覆盖
要查真实含 % 或 _ 的文本怎么办
用户搜 “50% off” 时,你不能直接拼 '%50% off%'——中间的 % 会被当通配符展开。必须先转义,再配合 ESCAPE 子句(仅 MySQL)或统一用函数处理(兼容性更好)。
安全做法(推荐):
- 先在 PHP 层转义:
$safe = str_replace(['%', '_'], ['\%', '\_'], $keyword) - SQL 中显式声明转义符:
WHERE name LIKE ? ESCAPE '\' - 绑定值用拼好的:
['%' . $safe . '%'] - 注意:PostgreSQL 和 SQLite 不支持
ESCAPE写法,应改用REPLACE(name, '_', '\_')+ESCAPE或改用正则(如~)
更稳妥的跨库方案是:把用户输入中的 % 和 _ 全部替换成其他不会冲突的字符(如 __pct__、__und__),再在字段上用 REPLACE() 预处理,但代价是索引失效——所以仅用于低频、明确需要字面匹配的场景。
ThinkPHP 等 ORM 框架里怎么写
ThinkPHP 的 array('like', '%xxx%') 写法底层仍走预处理,是安全的;但要注意数组结构别写错。
常见写法:
- 单字段模糊:
$where['title'] = ['like', '%' . $kw . '%']; - 多字段 OR:
$where['title|content'] = ['like', '%' . $kw . '%']; - 多关键词 OR:
$where['title'] = ['like', ['%' . $kw1 . '%', '%' . $kw2 . '%']]; - 多关键词 AND:
$where[] = ['like', '%' . $kw1 . '%']; $where[] = ['like', '%' . $kw2 . '%'];
陷阱:
- 别在数组外再用
str_replace或sprintf拼 SQL,会绕过预处理 - 分页时
Page类不支持数组值作为 URL 参数,需提前把 like 条件转成字符串存入$page->parameter - 用
whereRaw()或原生 SQL 时,必须手动确保所有变量都经过addslashes或quote(),不如直接走预处理
最易被忽略的一点:前后模糊(%xxx%)天然无法使用 B+ 树索引,哪怕字段加了索引也没用。如果搜索量大、响应慢,别只调优 SQL,优先考虑前缀索引、全文索引或引入 Elasticsearch —— 模糊不是万能解,而是性能妥协的起点。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











