json_encode不维护秩序

2022-08-30 17:13:05

我有一个多维数组,在PHP中:

Array
(
[1] => Array
    (
        [19] => Array
            (                    
                [type] => 2
            )            
        [6] => Array
            (                    
                [type] => 4
            )
        [12] => Array
            (                    
                [type] => 3
            )
    )

)

当我通过以下方式在javascript中json_encode这个数组时:

 var jsonArray = <?php echo json_encode($above_array); ?>;

我得到:

 Object
 (
 [1] => Object
 (
    [6] => Object
        (                    
            [type] => 2
        )
    [12] => Object
        (                    
            [type] => 4
        )
    [19] => Object
        (                    
            [type] => 3
        )
)

)

我想保留第一个订单,而不是id的第二个订单。


答案 1

有一个关于StackOverflow的问题 JavaScript是否保证对象属性顺序?简而言之,答案是否定的,事实并非如此。因此,当将PHP数组转换为Javascript对象时,键顺序将不会保留。

PHP和Javascript中数组之间的主要区别在于后者只能保存从零开始的顺序整数键。因此,并不总是能够将PHP数组转换为Javascript数组。让我们看几个例子:

// example 1
echo json_encode(array(0 => 'a', 1 => 'b')) // outputs ["a","b"]

// example 2
echo json_encode(array(0 => 'a', 3 => 'b')) // outputs {"0":"a","3":"b"}

// example 3
echo json_encode(array(3 => 'b', 0 => 'a')) // outputs {"3":"b","0":"a"}, but in Javascript the key order will be the same as in example 2
  1. 在第一个示例中,将 PHP 数组转换为相同的 Javascript 数组。json_encode
  2. 在第二个示例中,它转换为对象,因为键顺序不是顺序的。
  3. 在第三个示例中,它还转换为对象。但是在Javascript中,对象2和3将是相同的,具有相同的键顺序,即使键以不同的顺序列出。因此,不是函数不保留键顺序,而是Javascript本身。json_encode

回到我们的问题:如何将PHP数组传递给Javascript以保持密钥顺序?一种方法是将 PHP 键值对包装到数组中:

// original array:
array(
    3 => 'b', 
    0 => 'a'
)

// must be converted to:
array(
    array(3, 'b'),
    array(0, 'a')
)

然后将生成以下 Javascript 数组:json_encode

[
  [3,"b"],
  [0,"a"]
]

最后一部分是在Javascript中迭代这样一个数组:

var php_encoded_array = [
  [3,"b"],
  [0,"a"]
];

for (var i=0; i < php_encoded_array.length; i++) {
  var rec = php_encoded_array[i],
      key = rec[0],
      value = rec[1];

  console.log(key + ': ' + value);
}
// It will output:
// 3: b
// 0: a
// Which is the exact same order as in the PHP array

此方法还与非整数键兼容。

下面是用于在 PHP 端转换数组的代码(由 pr1001 在类似问题中建议)。它将适用于一维数组。

array_map(
    function($key, $value) { return array($key, $value); },
    array_keys($data),
    array_values($data)
)

下面是多维数组的递归函数实现:

function array_preserve_js_order(array $data) {
    return array_map(
        function($key, $value) {
            if (is_array($value)) {
                $value = array_preserve_js_order($value);
            }
            return array($key, $value);
        },
        array_keys($data),
        array_values($data)
    );
}

答案 2

问题在于,在 JavaScript 中,只有数组是有序的,对象不是。

如果你有类似的东西:

array(
    array(
        'type' => 2
        'id' => 6
    ),
    array(
        'type' => 4
        'id' => 12
    ),
    array(
        'type' => 3
        'id' => 19
    )
)

然后在你的JavaScript中,你会有一个对象数组,这个数组将保持它的顺序。

它无序的原因是数组的索引不是从 0 开始的,键不按顺序排列,并且键中存在间隙。因此,当编码时,PHP将其转换为对象而不是数组。