ThinkPHP返回集合数据应使用json()方法而非json_encode(),因其能正确处理模型类型转换、时间格式化、隐藏字段及访问器逻辑;直接json_encode()会暴露内部属性、忽略配置且导致时间字段格式错误。

ThinkPHP 返回集合数据为 JSON,直接用 json() 方法最稳妥,别手动 json_encode() —— 否则容易丢掉模型的自动类型转换、时间格式化和隐藏字段逻辑。
为什么不能直接 json_encode($collection)
ThinkPHP 的 Collection(比如 Db::table()->select() 或模型 ->select() 返回的)是对象,不是纯数组。直接 json_encode() 会触发 PHP 默认序列化行为,可能暴露内部属性、忽略 $hidden / $appends 配置,且时间字段变成时间戳或空字符串(取决于版本)。
常见错误现象:
• 返回 JSON 里出现 "_type":"collection" 字段
• created_at 变成 "2024-05-12 10:30:45" 或 1715509845,而不是预期的格式
• 模型定义的 getXXXAttr 访问器没执行
正确做法:
• 用 json() 方法(底层调用 toArray() + 自动处理)
• 或显式转数组再 json():json($collection->toArray())
• 不要自己 echo json_encode(...),绕过框架响应层会丢失 Content-Type 和状态码
立即学习“PHP免费学习笔记(深入)”;
json() 在不同场景下的写法差异
ThinkPHP 6.x 中,json() 是 think\Response 的方法,必须由控制器返回:
- 标准控制器方法:直接
return json($data);($data可以是数组、Collection、模型实例) - 带状态码和 header:
return json($data, 200, [], ['Content-Type' => 'application/json; charset=utf-8']); - 如果用了分页(
$list->render()),注意$list是Paginator对象,需先取数据:json($list->items())或更推荐json($list)(TP6.1+ 原生支持 Paginator 转 JSON) - 模型集合中含关联数据?确保关联已
with()预载入,否则json()时会 N+1 或报错
容易被忽略的坑:时间字段和 null 值处理
即使用了 json(),时间字段仍可能不符合前端预期,因为 TP 的时间自动转换依赖模型配置:
- 模型里没定义
protected $type = ['create_time' => 'datetime:Y-m-d H:i:s'];→ JSON 里还是时间戳整数 - 数据库字段为
NULL,但模型设置了protected $dateFormat = 'Y-m-d H:i:s';→NULL会被转成"0000-00-00 00:00:00"(TP6.0 默认行为),TP6.1+ 改为保持null - 全局关闭自动时间转换:
'datetime_format' => false在config/app.php,但不推荐,影响所有地方
性能提示:对大集合(如 >5000 条),json() 本身开销不大,但模型逐条转换访问器和关联会拖慢。此时应考虑用 Db::query() 或 Db::table()->field('id,name,...')->select() 直接查数组,再 json()。
真正麻烦的从来不是怎么输出 JSON,而是集合里混着未初始化的关联、动态追加的属性、或者自定义的 toJson() 方法覆盖了默认逻辑——这些地方一出错,json() 就静默失败或返回空。



















