24

I have a multi dimensional array, in PHP:

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

)

When i json_encode this array in javascript via:

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

i get:

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

)

I want to preserve the first order and not the second one by id.

meager
  • 209,754
  • 38
  • 307
  • 315
croppio.com
  • 1,673
  • 4
  • 25
  • 41
  • And how do i retain the first order? – croppio.com Jan 03 '14 at 20:54
  • use something else as the key (eg. key_1, key_2, key3) so you can sort after decoding json – Lorenzo Aiello Jan 03 '14 at 20:55
  • http://php.net/manual/en/function.json-encode.php#107616 – Amal Murali Jan 03 '14 at 20:56
  • 1
    JSON objects are unordered key-value maps. *Arrays* are ordered lists. Take your pick, Javascript/JSON doesn't have *ordered* maps. – deceze Jan 03 '14 at 20:57
  • If you want to retain order, you need an array, not an object. You'll need to generate a structure that looks like this: `[[19, {type: 2}], [9, { type: 2}], [6, {type: 4}], [12, {type: 3}]]` that is, an array of arrays, where each nested array contains two elements, the "index" and the `type` object. – meager Jan 03 '14 at 21:00
  • Possible duplicate of [How do you stop Chrome and Opera sorting JSON objects by Index ASC?](http://stackoverflow.com/questions/5020699/how-do-you-stop-chrome-and-opera-sorting-json-objects-by-index-asc) – Organic Advocate Jan 26 '17 at 20:42

3 Answers3

20

There's a question on StackOverflow Does JavaScript Guarantee Object Property Order? In short, the answer is no, it doesn't. So when converting a PHP array to a Javascript object, the key order will not be preserved.

The major difference between arrays in PHP and Javascript is that the latter can hold only sequential integer keys starting from zero. So it's not always possible to convert a PHP array to a Javascript array. Let's look at a few examples:

// 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. In the first example, json_encode converts a PHP array into an identical Javascript array.
  2. In the second example, it converts to an object, because the keys order is not sequential.
  3. In the third example, it also converts to an object. But in Javascript, the objects 2 and 3 will be the same, with the same key order, even though the keys are listed in a different order. So it's not json_encode function that is not preserving the key order, but Javascript itself.

Returning to our question: how to pass a PHP array to Javascript preserving the key order? One approach is to wrap PHP key-value pairs into arrays:

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

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

Then json_encode will result in the following Javascript array:

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

And the last part is iterating through such an array in 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

This approach is also compatible with non-integer keys.

Here's the code (suggested by pr1001 in a similar question) for converting an array on the PHP side. It will work for one-dimensional arrays.

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

And here's a recursive function implementation for multi-dimensional arrays:

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)
    );
}
Community
  • 1
  • 1
AlexM
  • 3,063
  • 2
  • 20
  • 24
6

The problem is that in JavaScript only arrays are ordered, objects are not.

If you had something like:

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

Then in your JavaScript you'd have an array of objects, and that array would retain its order.

The reason it's out of order is because your array's index didn't start at 0, the keys were not in order and there were gaps in the keys. So, when encoded, PHP turned it into an object instead of an array.

Rocket Hazmat
  • 204,503
  • 39
  • 283
  • 323
3

To preserve the order of PHP array, use array_values() function.

<?php $php_array = array_values($php_array); ?>
var jsonArray = JSON.parse('<?php echo json_encode($php_array); ?>');
Felix Jr
  • 345
  • 3
  • 7