You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Yii2 REST返回JSON时如何保留数据原始排序?

解决Yii2 REST接口JSON返回丢失原始排序的问题

我之前在做Yii2 REST项目时也踩过这个坑,太懂这种明明打印数组顺序正常,返回JSON就乱序的抓狂感了!

问题根源

这其实不是Yii2的锅,是PHP原生json_encode()的特性:当你传入的是数字键名的关联数组时,json_encode会自动把键按数字升序排列后再序列化。而XML序列化是严格按照数组的遍历顺序生成节点的,所以不会出现这个问题。

解决方案

根据你的业务需求,有两种靠谱的解决方式:

方案1:改用索引数组返回(推荐,符合REST规范)

如果业务允许,把以id为键的关联数组改成包含id字段的索引数组,这样JSON序列化会严格保留你查询时的排序:

public function actionIndex()
{
    // 你的关联查询逻辑,按priority降序获取数据
    $domains = Domain::find()
        ->with(['关联模型'])
        ->orderBy(['priority' => SORT_DESC])
        ->all();
    
    $result = [];
    foreach ($domains as $domain) {
        // 把id作为字段加入数组,而非键名
        $result[] = [
            'id' => $domain->id,
            'name' => $domain->name,
            'priority' => $domain->priority,
            // 其他需要返回的字段和关联数据
        ];
    }
    
    return $result;
}

这种方式不仅解决了排序问题,也更符合REST API返回资源列表的常规格式。

方案2:用ArrayObject包裹关联数组(保留键名结构)

如果必须保留id作为键名的结构,可以用PHP的ArrayObject来包裹你的关联数组。Yii2的JSON序列化器会把ArrayObject当作对象处理,从而保留原始键的顺序:

use ArrayObject;

public function actionIndex()
{
    // 你的数据查询和整理逻辑,得到以id为键的关联数组$domainData
    $domainData = ...;
    
    // 用ArrayObject包裹数组
    return new ArrayObject($domainData, ArrayObject::ARRAY_AS_PROPS);
}

或者你也可以在控制器里重写serializeData方法,全局处理这类情况:

use ArrayObject;

protected function serializeData($data)
{
    // 判断是否为数字键的关联数组
    if (is_array($data) && array_keys($data) !== range(0, count($data) - 1)) {
        $data = new ArrayObject($data);
    }
    return parent::serializeData($data);
}

为什么XML没问题?

XML序列化是直接遍历你的数组元素,按顺序生成对应的节点,不会像JSON序列化那样对数字键进行排序,所以原始顺序能被保留。

内容的提问来源于stack exchange,提问作者Vitaxxxa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:13:59