直接用 json() 方法最稳妥,因它自动调用 toarray() 并正确处理日期、访问器、关联、隐藏字段等;而直接 json_encode($model) 会触发默认序列化,导致闭包报错、时间输出为对象、漏掉 append 字段或关联数据、空关联返回 null 等问题。

直接用 json() 方法最稳妥,别先转数组再 json_encode() —— 模型里带日期、访问器、关联数据时容易出错。
为什么不能直接 json_encode($model)
ThinkPHP 模型对象不是普通 PHP 对象,它内部有 Carbon 实例、Collection、未初始化的关联属性、protected 属性等。直接 json_encode() 会触发默认序列化逻辑,可能:
- 抛出
Serialization of 'Closure' is not allowed(如果模型里定义了闭包访问器) - 把
created_at输出成对象而不是字符串(除非你重写了toJson()) - 漏掉
append字段或关联数据(因为没走模型的toArray()流程) - 对空关联返回
null而不是[],前端解析易报错
json() 方法怎么用才不出错
ThinkPHP 的模型和 Collection 都实现了 json() 方法,它会自动调用 toArray() + 合理处理时间、访问器、隐藏字段等。但要注意调用时机和上下文:
DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。
- 单个模型:
$user->json()→ 返回think\Response对象,可直接return - 集合查询:
User::with('profile')->select()->json()→ 自动深转关联 - 控制器中推荐写法:
return json($user);或return json($list);(框架会自动识别并调用json()) - 如果要加 HTTP 状态码或 header:
return json($data)->code(200)->header(['Cache-Control' => 'no-cache']);
需要自定义 JSON 输出结构时怎么办
比如想统一加 code/msg 包裹,或过滤敏感字段,别在控制器里手动拼数组。更可靠的方式是:
- 在模型里重写
toArray(),控制字段粒度:protected $hidden = ['password', 'salt']; - 用
append补充计算字段:protected $append = ['is_vip'];,并在getIsVipAttr()里写逻辑 - 对时间字段格式统一控制:
protected $dateFormat = 'Y-m-d H:i:s'; - 如果必须外层包壳,用独立方法封装,避免每个接口都重复写:
return $this->success($user);,其中success()内部调用json(['code' => 0, 'data' => $user->toArray()])
关联数据没转成数组?检查 with() 和 toArray() 的配合
很多人发现 User::with('posts')->find(1)->toArray() 里 posts 还是 Collection 对象 —— 这是因为 toArray() 默认只转当前层,而 posts 是关联模型集合,它的 toArray() 不会自动递归调用(除非你显式配置)。
- 确保关联方法返回的是
Model或Collection(不是原始数组),否则toArray()不生效 - 5.1+ / 6.x 中,
with()查询后调用json()是安全的,它会穿透所有层级 - 如果非要手动深转,且数据量不大,可用:
json_decode(json_encode($model), true),但注意:模型里有不可序列化内容(如 PDO、resource)会崩 - 别用
Collection::make($model)->toArray(),这是多余嵌套,反而让结构变复杂
真正容易被忽略的是:模型的 json() 行为依赖 toArray(),而 toArray() 又受 $hidden、$visible、$append、访问器、类型转换共同影响——改一个地方,JSON 输出就可能变。调试时优先查模型定义,而不是在接口层硬 patch。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










