直接用json_encode($model)与先toarray()再json_encode()结果不同,因前者仅序列化public属性且忽略框架逻辑,后者通过yii2语义化导出完整、安全、可控的数组。

直接用 json_encode($model) 和先调 toArray() 再 json_encode(),结果往往不一样——关键不在 JSON 编码本身,而在于“传给 json_encode 的到底是什么数据”。
对象直转 JSON 会暴露内部结构
PHP 原生 json_encode 只能访问对象的 public 属性。Yii2 模型里的 $attributes、$oldAttributes、$errors、$scenario 等都是 protected 或 private,不会被编码进去。但如果你没重写 __toString 或实现 JsonSerializable,它可能把整个对象当成空对象或报错;更常见的是,它会尝试遍历 public 成员,结果漏掉业务字段,或者意外带上调试用的临时属性。
例如:
-
json_encode($user)→ 可能输出{}或只含几个 public 字段,甚至触发Recursion detected -
json_encode($user->toArray())→ 输出完整、可控的关联数组,字段由fields()和extraFields()决定
toArray() 是 Yii2 的语义化导出入口
toArray() 不是简单反射属性,它按框架约定执行一整套逻辑:
- 自动过滤
$hidden中声明的字段(如密码哈希) - 触发
getXXX()访问器(比如把created_at转成格式化时间) - 展开已加载的关联模型(
with(['profile', 'orders'])后,toArray()会包含对应数据) - 应用
$casts类型转换(如把数据库 int 存的 status 转成字符串 'active') - 尊重
fields()自定义白名单,避免敏感字段泄露
这些步骤在 json_encode($model) 里全都不会发生。
toJson() 就是 toArray() + json_encode()
Yii2 模型自带的 toJson() 方法,底层就是先调 toArray(),再 json_encode()。所以:
-
$user->toJson()≡json_encode($user->toArray()) - 两者结果一致,且都安全、可预测
- 如果需要加 JSON 选项(如
JSON_PRETTY_PRINT或JSON_UNESCAPED_UNICODE),推荐用json_encode($user->toArray(), JSON_UNESCAPED_UNICODE)
什么时候可以跳过 toArray()?
极少情况可直转:
- 你确认该对象已实现
JsonSerializable接口,并重写了jsonSerialize()方法,且逻辑等价于toArray() - 你处理的是纯 DTO 对象(所有属性 public,无业务逻辑、无关联、无访问器),且明确不需要框架层的字段控制
- 调试时快速看结构,但生产代码中不建议
绕过 toArray() 最常见的后果:返回空对象、字段缺失、抛出递归异常、暴露不该暴露的内部状态。











