直接写 $this->db->where() 多次会导致重复代码和维护困难,因条件组合复杂易成面条代码且多处复制难统一修改;my_model::helpbuildwhere() 通过识别数组结构递归调用原生查询构造器,安全兼容事务。

为什么直接写 $this->db->where() 多次会重复又难维护
当一个查询要支持「按状态筛选 + 按时间范围筛选 + 可选按分类 or 分组」时,if 嵌套里反复调用 $this->db->where()、$this->db->or_where()、$this->db->group_start(),很快就会变成面条代码。更麻烦的是:同一套条件逻辑在多个控制器方法里复制粘贴,改一处漏三处;一旦数据库字段名变更或运算符调整(比如 like 改成 like binary),所有地方都得手动搜改。
MY_Model::helpBuildWhere() 怎么把数组转成合法查询条件
核心是识别数组结构并递归分发到对应方法。它不依赖 SQL 字符串拼接,而是复用 CI 原生的查询构造器链式调用,安全且兼容事务。
- 单字段单条件:
['status' => ['=', 1]]→ 调用$db->where('status', 1) - 单字段多条件:
['price' => [['>=', 10], [' → 循环调用 <code>$db->where(),自动合并为AND - or 分组:
['or_group' => ['type' => ['=', 'A'], 'flag' => ['!=', 0]]]→ 先$db->or_group_start(),再递归处理子数组,最后$db->group_end() - not 分组:
['not_group' => [...]]同理,走$db->not_group_start()
注意:键名必须严格匹配预设正则 ^(or_not_group|not_group|or_group|group)\d{0,2}$,否则会被当作普通字段处理。
封装后怎么避免 where 条件被意外覆盖或遗漏
原生 CI 的 $this->db 是共享实例,如果在模型方法中没重置就反复调用 helpBuildWhere(),上一次的 where 会残留。必须显式控制作用域:
- 传入独立
$db实例(如从$this->load->database('backup', TRUE)获取)可完全隔离 - 若复用主库,建议每次查询前先调用
$this->db->reset_query(),清空where、select、join等缓存 - 不要在
helpBuildWhere()内部调用get()或count_all_results()—— 它只负责“构建”,执行交给上层决定
实际使用时最容易踩的坑
不是语法错误,而是语义误解:
-
['or_group' => ['a' => ['=', 1], 'b' => ['=', 2]]]生成的是(a = 1 OR b = 2),不是(a = 1) OR (b = 2)—— 括号层级由分组函数控制,不是靠 key 名字 -
unset($data['id'])这种操作在条件数组里无效;真正要过滤的是传入helpBuildWhere()的数组本身,不是数据库结果对象 - 如果条件数组里混入了
null或空字符串,metaOpe()默认仍会生成WHERE field = '',需提前array_filter()清洗
复杂嵌套分组和动态 or/and 切换,靠数组结构很难一眼看清最终 SQL 逻辑,调试时建议在关键位置加 echo $this->db->last_query(); 看真实生成语句。











