views:

101

answers:

4

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 
+1  A: 

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

philfreo
you missed 3rd line, where the object was converted to an array. your answer doesn't explain why do we can see the item in var_dump() but cannot access it. the general question is about `object->array` conversion and not about how to work with `json_decode`
zerkms
philfreo thank you. this helps me go on with my coding. but I well keep the question open now and maybe someone explains the unexpected behaviour that I found. OP karlthorwald - aka
+1  A: 

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>';
Alix Axel
This doesn't justify the results anyway ;-) Does it?
zerkms
+3  A: 

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.

Alan Storm
Still, if you `print_r()` the `$a` after it has been casted as an array you can clearly see that the index `0` hasn't been dropped.
Alix Axel
yep. agreed with @Alix. the explanation in http://stackoverflow.com/questions/1869812/casing-an-array-with-numeric-keys-as-an-object works for objects. but due to we explicitly casted object to array we expect that it will work in regular way. even if new array wouldn't contain that "malformed key" - it also can be explained (because of malformed property of object). but semi-functional array looks very buggy.
zerkms
Updated question to address other the comments. In the case of $a you're casting **an already invalid object** as an array, so you're entering undefined behavior territory and all bets are off. In the case of $b PHP automatically casts the "0" as an int to produce a valid array. I agree it's weird behavior, but you end up with similar weird behaviors in any language that eschews strong typing.
Alan Storm
yep, the last update with `string vs integer` keys comparison clarifies this php behavior. thanks.
zerkms
+1  A: 
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.

bobince
`var_dump`, actually
zerkms
It helps a lot to know that print_r does not work well. Still var_export shows a string key (see extended example in the question)