json_encode sometimes does or does not add keys for array elements

I discovered the other day that I json_encode was converting php arrays into json and sometimes, but sometimes not, adding indexes to elements.

$array1 = array(
	'first',
	array('second'=> 'third',
	      'fourth' => 'fifth'
	),
	arrays('sixth' => 'seventh'),
);
var_dump(json_encode($array1)); // output: '["first",{"second":"third","fourth":"fifth"},{"sixth":"seventh"}]'
   
// first element in the array is now associative:

$array2 = array(
	'first' => 'new value',
	array('second'=> 'third',
	      'fourth' => 'fifth'
	),
	arrays('sixth' => 'seventh'),
);

var_dump(json_encode($array2)); // output: '["first":"new value',"0":{"second":"third","fourth":"fifth"},"1": {"sixth":"seventh"}]'

Can someone explain this behavior to me? I want to be able to create multidimensional arrays where the sub-arrays are not associated with a key in json, as in the first example. Whether or not json_encode gives sub arrays explicit keys appears to depend on whether the top most array in the multidimensional array has an explicitly associative element in it (‘first’ => ‘subvalue’ instead of just 'first). But that is all I could find from testing various arrays and json_encoding them.

What determines whether json_encode adds array keys or not, and can the behavior be explicitly controlled?

TL:DR; use json_encode(array_values($array2)) to produce JSON arrays [indexed].


I always have a hard time explaining why your example behaves like that, so here’s the overly wordy version:

PHP doesn’t distinguish between indexed and associative array, all arrays are associative and that’s that [ref PHP doc]. PHP’s JSON encoder does distinguish the two. In fact, it must as only indexed arrays are valid under JSON [ref RFC 4627, Section 1: Introduction].

Because of this, json_encode needs to make assumptions. If a PHP array does not have any explicitly defined keys OR if all the keys - after being typecast* - are not perfectly sequential from 0…X then the PHP array becomes a JSON array [indexed].

If on the other hand the PHP array has at least one defined key OR the keys are not sequential then it automatically becomes a JSON object.

I’m about to pass out, so I’ll just throw this here:

json_encode($array1, JSON_FORCE_OBJECT); // Forces the JSON to be an object, not an indexed (see below)
json_decode($array1, true); // Forces the resulting PHP array to have explicitly defined keys [Associative]

If you only want the values (you want an indexed JSON array), just go with the json_encode(array_values($array2))


Notes:

*. To confuse things further, array-key typecasting in PHP seems quirky itself. For example, this:

$array = array(
    1    => "a",
    "1"  => "b",
    1.5  => "c",
    true => "d",
);

would only output this:

array(1) {
  [1]=>
  string(1) "d"
}
2 Likes

Thanks OzRamos. Hmm… I was aware of some of the difference between arrays in PHP and other languages, but this helps alot to understand the conversion taking place. I’ll have to experiment some more to get the arrays to come out how I want, but this is some great foundational knowledge, thanks.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.