优先使用 result_array() 而非手动封装对象转数组逻辑,因其避免 null 值、类型不一致及空结果集等边界问题;CI3/CI4 中 result() 返回对象数组,result_array() 返回关联数组,后者字段访问更安全、判断更直接。

直接用 result_array() 就够了,别自己封装对象转数组逻辑——除非你明确需要控制字段映射、过滤或类型转换。CodeIgniter 自带的方法已足够健壮,手动遍历 result() 再逐个取属性反而容易漏掉 null 值、类型不一致或空结果集的边界情况。
CI3/CI4 中 result() 和 result_array() 的本质区别
两者都返回全部结果,但底层结构不同:result() 返回的是 stdClass 对象数组(每个元素是对象),result_array() 直接返回关联数组数组(每个元素是 array)。CI4 的查询构造器默认返回 Query 实例,必须显式调用其中一个方法才能拿到数据。
-
result()在字段名含特殊字符(如连字符、数字开头)时可能无法用箭头访问,得用$row->{'field-name'} -
result_array()不存在属性访问问题,且可直接用isset($row['field'])判断字段是否存在 - CI4 中若用
get()->getResult(),等价于 CI3 的query()->result();get()->getResultArray()等价于query()->result_array()
什么时候真需要自定义封装?
只有当你要做以下事情之一时,才值得写额外封装:
- 统一把数据库里的
datetime字段转成毫秒级时间戳,比如date_issued→strtotime($row['date_issued']) * 1000 - 强制将字符串数字转为 float/int,避免前端 JSON 解析后仍是字符串(尤其影响图表库数值轴)
- 剔除敏感字段(如
password_hash)、重命名字段(user_id→id)、补默认值(status为空时设为'pending') - 把一对多关系“扁平化”成嵌套数组(例如一个用户带多个订单,想合并成
['orders' => [...]])
这种封装建议放在 Model 层,而不是 Controller 或通用工具函数里——因为字段语义和业务强相关。
封装示例:带类型转换的轻量级数组转换
假设模型返回原始数据 $raw = $this->db->query($sql)->result_array(),你需要转成前端图表所需的 [[timestamp, value], ...] 格式:
$converted = [];
foreach ($raw as $row) {
$ts = strtotime($row['date_issued']) * 1000 ?? 0;
$val = (float) $row['grand_total'];
$converted[] = [$ts, $val];
}
$response['price'] = $converted;
注意这三处易错点:
- 别用
strtotime()处理非标准格式日期(如'01/15/2025'),先用DateTime::createFromFormat()校验 -
(float)强转遇到空字符串或null会变成0.0,如果业务上0是有效值,得先if (empty($row['grand_total'])) continue; - CI4 中若用 Query Builder,别写
$this->db->query($sql)->result_array(),优先用$this->table('invoices')->select('date_issued, grand_total')->get()->getResultArray()——更安全、可被 Query Caching 拦截
真正麻烦的不是“怎么转”,而是“哪些字段要转、按什么规则转、空值怎么兜底”。这些逻辑一旦散落在 Controller 里,很快就会变成维护噩梦。把转换规则收口到 Model 的一个 protected 方法里,比写十个“万能封装函数”靠谱得多。











