Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSON object conversion question

I am converting from JSON to object and from object to array. It does not what I expected, can you explain to me?

$json = '{"0" : "a"}';
$obj = json_decode($json);
$a = (array) $obj;
print_r($a);
echo("a0:".$a["0"]."<br>");

$b = array("0" => "b");
print_r($b);
echo("b0:".$b["0"]."<br>");

The output here is:

Array ( [0] => a ) a0:
Array ( [0] => b ) b0:b

I would have expected a0:a at the end of the first line.

Edit: After reading the answers I extended the code, which makes the behaviour more clear:

//extended example
$json = '{"0" : "a"}';
$obj = json_decode($json);
$a = (array) $obj;
var_export($a);
echo("a0:".$a["0"]."<br>"); //this line does not work, see the answers
echo $obj->{"0"}."<br>";  //works!

$json = '{"x" : "b"}';
$obj = json_decode($json);
$b = (array) $obj;
var_export($b);
echo("bx:".$b["x"]."<br>");

$c = array("1" => "c");
var_export($c);
echo("c1:".$c["1"]."<br>");

$d = array("0" => "d");
var_export($d);
echo("d0:".$d["0"]."<br>");

Output of extended example:

array ( '0' => 'a', )a0:
a
array ( 'x' => 'b', )bx:b
array ( 1 => 'c', )c1:c
array ( 0 => 'd', )d0:d 
like image 958
user89021 Avatar asked May 17 '10 23:05

user89021


4 Answers

There's more information in this older question. The short version is that properties on PHP objects/classes follow the same naming convention as variables. A numerical property is invalid on a PHP object, so there's no clear rule as to what should happen when serializing an object from another language (json/javascript) that has a numerical key. While it seems obvious to you what should happen with the above, someone with a different bias sees PHP's behavior in this instance as perfectly valid and preferred.

So, it's kind of a bug, but more an undefined area of the spec with no clear answer, so don't expect the behavior to change to meet your liking, and if it does change, don't expect that change to be permanent.

To address some of the issues in the comments, consider this

header('Content-Type: text/plain');
$json = '{"0" : "a"}';
$obj = json_decode($json);
$a = (array) $obj;
var_dump($a);
var_dump(array(0=>'a'));
var_dump(array('0'=>'a'));

that will output something like this

array(1) {
  ["0"]=>
  string(1) "a"
}
array(1) {
  [0]=>
  string(1) "a"
}
array(1) {
  [0]=>
  string(1) "a"
}

An array with a single string key zero isn't a valid PHP construct. If you try to create one PHP will turn the zero into an int for you. When you ask PHP to do a cast it doesn't have a definition for, it ends up creating an array with a string key (because of the ill defined rules around what should happen here).

While it's blatantly obvious that this is "wrong" behavior on the part of PHP, defining the right behavior in a language that's weakly typed isn't easy.

like image 96
Alan Storm Avatar answered Oct 26 '22 02:10

Alan Storm


You can just access it as an object (stdClass) rather than an array:

$json = '{"0" : "a"}';
$obj = json_decode($json);
print_r($obj);
echo("a0:".$obj->{"0"}."<br>");

This is the most straightforward since your JavaScript was an object ({}) rather than an array [] to begin with.

Alternatively, you can do this

$arr = json_decode($json, true);

The second optional parameter makes it output an associative array. http://us.php.net/json_decode

like image 20
philfreo Avatar answered Oct 26 '22 02:10

philfreo


Why are you doing this? Do you know you can have the JSON decoded values as an array directly?

$arr = json_decode($json, true);

echo '<pre>';
print_r($arr);
echo '</pre>';
like image 1
Alix Axel Avatar answered Oct 26 '22 01:10

Alix Axel


Array ( [0] => a ) a0:
Array ( [0] => b ) b0:b

PHP's unhelpful print_r attacks again!

The first array has an integer key 0, because the (array) cast tries to turn it into a flat list-like array.

The second array retains the associative-array-style string key '0' you constructed it with.

Use var_export instead of print_r and you can see the difference more easily.

like image 1
bobince Avatar answered Oct 26 '22 02:10

bobince