thinkphp同字段多次where()调用会覆盖而非叠加,如where('id',1)->where('id',2)最终仅生效id=2;动态拼接须先判空再入数组,复杂逻辑必须用闭包分组确保括号层级正确。

同字段多次 where() 调用会覆盖,不是叠加
ThinkPHP 的 where() 对同一字段重复调用时,后一次直接替换前一次,不会生成 IN 或 OR。比如:
User::where('id', 1)->where('id', 2)->select()
实际生成的 SQL 是 WHERE id = 2,id = 1 彻底丢失。
- 循环中动态加条件时,必须先判断值是否有效,再决定是否写入数组,而不是无脑
$query->where($k, $v) - 想查多个 ID,得用
where('id', 'in', [1, 2, 3]),不能靠多次where('id', X) - 字段名拼错(如
'statuss')也不会报错,只会默默忽略该条件——建议开启 ThinkPHP 的debug模式看最终 SQL
where() 数组传参时,空值、null、0 都算“有效条件”
TP5/6 中,where(['name' => '']) 会生成 WHERE name = '',不是跳过;where(['score' => 0]) 同理。这和直觉相反,但确实是默认行为。
- 表单搜索时,用户没填关键词,
$input['keyword']是空字符串,直接where('title', $input['keyword'])就会查出所有 title 为空的记录 - 正确做法是显式判空:
if (!empty($input['keyword'])) { $where['title'] = ['like', "%{$input['keyword']}%"]; } -
null值要走whereNull()或whereNotNull(),别塞进数组里当普通值用
用 whereRaw() 或字符串拼接 WHERE 就等于裸写 SQL
像 whereRaw("name LIKE '%{$name}%'") 或 where("status = {$status}") 这类写法,完全绕过参数绑定,只要 $name 来自用户输入,就是 SQL 注入漏洞。
- 哪怕加了
htmlspecialchars()也没用,它防 XSS,不防 SQL 注入 - 模糊查询必须用占位符:
where('name', 'like', "%{$name}%")(TP 自动绑定),或 PDO 手动绑定:name并在 execute 时传[':name' => "%{$name}%"] -
whereRaw()只应在极少数必须手写表达式时使用,且所有变量必须用?或:param占位,并通过第二个参数绑定
复杂逻辑不用闭包包裹,括号层级就失控
想表达 (status = 1 OR type = 'vip') AND deleted_at IS NULL,如果写成:
User::where('status', 1)->whereOr('type', 'vip')->whereNull('deleted_at')
实际生成的是 WHERE status = 1 OR type = 'vip' AND deleted_at IS NULL,等价于 status = 1 OR (type = 'vip' AND deleted_at IS NULL),和预期不符。
- OR 和 AND 混合时,必须用闭包明确分组:
where(function ($q) { $q->where('status', 1)->whereOr('type', 'vip'); }) - 多层嵌套(比如 A OR B AND C OR D)必须拆成多个闭包,不能指望链式自动加括号
- 闭包里用的
$q是子查询对象,和外部$query独立,变量作用域别搞混
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











