核心问题是asarray()返回含datetime对象的纯数组,导致json_encode()失败或字段缺失;toarray()则通过fields()可控地格式化时间字段为字符串,确保json序列化正常。

核心问题不在 asArray() 和 toArray() 本身,而在于它们返回的数据结构不同,导致后续 JSON 序列化时对 DateTime 对象的处理路径完全分离——一个走 PHP 原生序列化逻辑,另一个走 Yii 的模型字段转换逻辑。
asArray() 返回纯数组,DateTime 字段直接暴露为对象
asArray() 的结果是“扁平数组”,但若模型中某字段(如 created_at)在数据库里是 DATETIME 类型,且你没显式 cast 或格式化,ActiveRecord 默认会把它映射为 DateTime 实例。这个对象进入 json_encode() 时,PHP 不知道怎么序列化,结果通常是空、null,或触发错误(取决于 json_encode 的严格模式)。它不会自动转成时间字符串,更不会按你期望的格式(如 Y-m-d H:i:s)输出。
- 示例:
$model->asArray()['created_at']可能是object(DateTime),不是字符串 - 后果:JSON 响应里该字段缺失、为
null,或整个响应体为空(因json_encode失败返回false)
toArray() 返回模型对象数组,受 attributeMap 和 field() 控制
toArray() 是 ActiveRecord 的方法,它会调用模型定义的 fields() 或 extraFields(),并尊重你在其中对时间字段做的格式化。比如你重写了 fields():
public function fields()
{
$fields = parent::fields();
$fields['created_at'] = function () {
return $this->created_at ? $this->created_at->format('Y-m-d H:i:s') : null;
};
return $fields;
}
这时 toArray() 输出的就是字符串,json_encode() 能直接处理。
- 关键点:格式由你代码控制,不依赖 PHP 默认行为
- 风险:如果没重写
fields(),toArray()仍可能把DateTime对象原样塞进去,结果和asArray()一样
混用时时间格式错乱的典型场景
你在一个接口里,部分数据用 asArray(),部分用 toArray(),又没统一处理时间字段:
-
$user->asArray()→updated_at是DateTime对象 → JSON 里消失 -
$profile->toArray()→updated_at已被fields()格式化为字符串 → JSON 里正常显示 - 前端看到同一接口里有的时间有、有的没有,或格式不一致(如一个带毫秒、一个不带)
统一时间格式的实操建议
- 避免混用:选定一种方式并贯穿始终。API 接口推荐统一用
toArray(),并重写fields()显式控制每个时间字段输出 - 若必须用
asArray(),先做预处理:array_map()或循环中手动调用format()把时间字段转成字符串 - 全局兜底:在
JsonResponseFormatter的encodeOptions中加JSON_PARTIAL_OUTPUT_ON_ERROR(PHP 7.3+),让出错字段至少不中断整个响应 - 调试时用
var_dump(json_last_error_msg())确认是否因DateTime导致编码失败







