PHP/json_encode: dealing with mixed arrays and objects with numeric properties PHP/json_encode: dealing with mixed arrays and objects with numeric properties json json

PHP/json_encode: dealing with mixed arrays and objects with numeric properties


When calling json_encode on an array list, with numeric coherent indexes starting with 0, PHP will treat the list as an indexed array, and not an associative array. To force php to treat it as an associative array, you can cast the array to an object before calling json_encode.

Example:

$somelist = ["item A", "item B"];$ratings = [0.001234, 0.666, 0.09876, 0.777777];$final = ['someList' => $somelist, 'ratings' => (object) $ratings];echo json_encode($final);

Output:

{["item A","item B"],{"0":0.001234,"1":0.666,"2":0.09876,"3":0.777777}}


I've also struggled with returning JSON with both regular arrays and objects with numeric keys in the same response.

A solution I found is that you can build up a stdObject and defining the keys using $obj->{'0'} for example.

Here's a full example:

$decoded = json_decode('{  "someList": [    "item A",    "item B"  ],  "ratings": {    "0": 0.001234,    "1": 0.0666,    "2": 0.09876,    "3": 0.777777  }}', true);// Do stuff with $decoded['ratings']$ratings = new \stdClass;foreach ($decoded['ratings'] as $key => $rating) {    $ratings->{$key} = $rating;}echo json_encode([    'someList' => $decoded['someList'],    'ratings' => $ratings]);

Which then will output the following:

{  "someList": [    "item A",    "item B"  ],  "ratings": {    "0": 0.001234,    "1": 0.0666,    "2": 0.09876,    "3": 0.777777  }}


I wouldn't normally suggest "building" JSON manually, but concatenating bits of valid JSON should be fairly safe, and I think it's the only way you'll get this working.

$somelist = ["item A", "item B"];$ratings = [0.001234, 0.666, 0.09876, 0.777777];$json = sprintf(    '{"somelist":%s,"ratings":%s}',    json_encode($somelist),    json_encode($ratings, JSON_FORCE_OBJECT));echo $json;

Or in case you have a larger object to work with, you can loop over the data to do this programmatically.

$original_json = '{"someList":["item A","item B"],"ratings""{"0":0.001234,"1":0.0666,"2":0.09876,"3":0.777777}}';$data = json_decode($original_json);// do whatever you need to do with the dataarray_walk($data->someList, function(&$v, $k){$v .= " is changed";});$vsprintf_args = [];$format_str = "{";foreach($data as $k=>$v) {    $format_str .= '%s:%s,';    $vsprintf_args[] = json_encode($k);    $vsprintf_args[] = json_encode($v, ($k === "ratings" ? JSON_FORCE_OBJECT : 0));}$format_str = trim($format_str, ",") . "}";$json = vsprintf($format_str, $vsprintf_args);echo $json;

Output:

{"somelist":["item A","item B"],"ratings":{"0":0.001234,"1":0.666,"2":0.09876,"3":0.777777}}