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
相关产品推荐
相关产品推荐

