2

I've got some very weird behavior in my PHP code. I don't know if this is actually a good SO question, since it almost looks like a bug in PHP. I had this problem in a project of mine and isolated the problem:

// json object that will be converted into an array
$json = '{"5":"88"}';
$jsonvar = (array) json_decode($json); // notice: Casting to an array
// Displaying the array:
var_dump($jsonvar);
// Testing if the key is there
var_dump(isset($jsonvar["5"]));
var_dump(isset($jsonvar[5]));

That code outputs the following:

array(1) {
  ["5"]=>
  string(2) "88"
}
bool(false)
bool(false)

The big problem: Both of those tests should produce bool(true) - if you create the same array using regular php arrays, this is what you'll see:

// Let's create a similar PHP array in a regular manner:
$phparr = array("5" => "88");
// Displaying the array:
var_dump($phparr);
// Testing if the key is there
var_dump(isset($phparr["5"]));
var_dump(isset($phparr[5]));

The output of that:

array(1) {
  [5]=>
  string(2) "88"
}
bool(true)
bool(true)

So this doesn't really make sense. I've tested this on two different installations of PHP/apache.

You can copy-paste the code to a php file yourself to test it.

It must have something to do with the casting from an object to an array.

1
  • Does passing true as the second arcument to json_decode instead of casting the return value help? Commented Apr 4, 2010 at 15:17

4 Answers 4

5

Use the json_decode function parameters to get an array, instead of changing an object yourself.

json_decode ( string $json [, bool $assoc = false])
$assoc - When TRUE, returned object s will be converted into associative array s.

Your code, when changed to

$jsonvar = json_decode($json, true);

works as expected

Sign up to request clarification or add additional context in comments.

1 Comment

This is true, but I would still like to know why it doesn't match the key, no matter what the origin of the array is.
3

It can be further simplified to this problem

$o = new stdClass;
$o->{5} = 1; //or even $o->{'5'} = 1;
$a = (array) $o;
print_r($a); // Array([5] => 1)
var_dump(isset($a[5])); // false
var_dump(isset($a['5'])); // false

It seems that this only happens when the property name is one that php would normally consider a numeric key in an array.

Definitely unexpected behavior to me.


edit Same issue here Casting an Array with Numeric Keys as an Object


edit#2 documented behavior http://www.php.net/manual/en/language.types.array.php#language.types.array.casting

2 Comments

It's documented but still a bit annoying. For arrays php always tests whether the key is somehow numeric, e.g. $a['5'] will treat 5 as a numeric key (and marks the bucket for the hashtable with keylength=0). Objects on the other hand treat numerical indices always as string, e.g. $o->{5} creates a string key in the properties hashtable of that object. When an object is cast to array the properties hashtable is more or less copied as-is, i.e. the behavior of the keys isn't converted as well. That's probably a speed optimization.
Ya I noticed some of that when digging through the source for zend_hash.c a while back. A dev did state they aren't changing it due to performance reasons bugs.php.net/bug.php?id=45959
2

As chris said, you are hitting one of the limits of the json <-> object <-> array mappings.

Another interesting one to keep in mind is when a key in a json object is the empty string.

json = '{"":"88"}';

the key will be mapped to php as "empty" !

1 Comment

This is no longer accurate as of php7 - it works now. 3v4l.org/tvHNQ php7 uses a new json backend, so I would expect lots of behavior to change, such as this.
0

Use a statement like

$value = $a["'".$i."'"];

directly following the line that goes

$a = json_decode($a, true);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.