3

I have an array. Here is it's var_dump:

array(1) {
 ["139"]=>
 string(5) "my_data"
}

We see, that we have key 139, and it's string (var dumps of key: string(3) "139"). I want to get element from array, here's the code:

$bad_array = $this->get('some_data');
var_dump($bad_array);
var_dump($my_key);
var_dump(isset($bad_array[$my_key]));
var_dump($bad_array[$my_key]);

Here's the output:

array(1) {
 ["139"]=>
 string(5) "my_data"
}
string(3) "139" // my key output
bool(false) // it's not isset
Notice: Undefined index: 139 in /my_file_path.php on line 89
NULL

WHY??? I have a string variable, all of keys are strings. How can it be?

Dai
158k31 gold badges314 silver badges439 bronze badges
asked Jan 23, 2014 at 9:52
16
  • 3
    It's odd that you get string(5) for "my_data" Commented Jan 23, 2014 at 9:54
  • 2
    Try var_dump(bin2hex($my_key), bin2hex(key($bad_array))) and see what you get. Commented Jan 23, 2014 at 9:55
  • 1
    Please post your code that constructs the array. Commented Jan 23, 2014 at 9:56
  • @Ryan for me it looks like that this is the value for var_dump($bad_array); @HAL9000 it contains string(3) "139" as you can see Commented Jan 23, 2014 at 9:56
  • @Ryan. It's my mistake. I changed the code in post slightly for clarity. There is 5char string in my app. Commented Jan 23, 2014 at 9:56

2 Answers 2

3

Short Answer

Array type-casting from an Object doesn't work with integer properties (as strings i.e. "139").

Long answer

A bunch of testing code :

<pre>
<?php
 $arr = array("139" => "some_data", "test" => "other_data");
 
 $good = (object) $arr;
 $good_arr = (array) $good;
 
 $bad = json_decode(json_encode($arr));
 $bad_arr = (array)($bad);
 
 var_dump ($arr);
 foreach ($arr as $k => $v)
 var_dump (gettype ($k)); // 139 is integer
 
 var_dump ($good);
 foreach ($good as $k => $v)
 var_dump (gettype ($k)); // 139 is integer
 
 var_dump ($good_arr);
 foreach ($good_arr as $k => $v)
 var_dump (gettype ($k)); // 139 is integer
 var_dump ($bad);
 foreach ($bad as $k => $v)
 var_dump (gettype ($k)); // 139 is string
 var_dump ($bad_arr);
 foreach ($bad_arr as $k => $v)
 var_dump (gettype ($k)); // 139 is string
 var_dump ($arr[139]); // string(9) "some_data"
 var_dump ($arr["139"]); // string(9) "some_data"
 var_dump ($arr["test"]); // string(10) "other_data"
 
 var_dump ($good->{139}); // NULL
 var_dump ($good->{"139"}); // NULL
 var_dump ($good->{"test"}); // string(10) "other_data"
 
 var_dump ($good_arr[139]); // string(9) "some_data"
 var_dump ($good_arr["139"]); // string(9) "some_data"
 var_dump ($good_arr["test"]); // string(10) "other_data"
 
 var_dump ($bad->{139}); // string(9) "some_data"
 var_dump ($bad->{"139"}); // string(9) "some_data"
 var_dump ($bad->{"test"}); // string(10) "other_data"
 
 var_dump ($bad_arr[139]); // NULL
 var_dump ($bad_arr["139"]); // NULL
 var_dump ($bad_arr["test"]); // string(10) "other_data"
?>
</pre>

bin2hex is actually showing exactly the same value, and foreach was working fine.

So how is that possible that it doesn't work when we're trying to access it directly ?
And how weird is it that the last is displaying fine ?

Well, actually, I got the answer to the second question from this part from the doc talking about array type casting As you can see there, when converting an object to array with type casting, this doesn't work for number properties, which are let inaccessible.

For the first question, I will assume that the type cast doesn't change how data are represented in memory, so that it can still iterate on it as if it was an object.

Next are just my assumptions of differences between both scenarios :

In the good scenario

PHP is handling stuff all by himself. An array key of type string representing an integer is automatically converted to integer.
Then, no problem when we convert it, it becomes a property (with integer type) of the $good object even though it isn't accessible (because it is trying to reach the "139" property, not the 139). (NULL returned)
When we do the cast to array $good_arr, the data structure hasn't changed, and we can still access it, because it reaches 139 and not "139".

In the bad scenario

Here the object is regenerated by json_decode. This function doesn't generate bad objects (and tht's a good thing !), so all the properties will have type string.
This is why we can access the property directly from the object here. It is a valid property (type string) so we can access it.
But as told in the docs, when we cast it back to array, the data structure hasn't changed, so we can't access it. Either we write $bad_arr[139] or $bad_arr["139"] it will try to access to the value with the key 139 (NULL returned), when it should actually access "139".

Conclusion

This is a typical example of PHP's magic. Converting strings to int automatically in arrays is what caused your problem.

So your solution of using the assoc param of json_decode seems to be the only one which will work here :

json_decode($json_arr, true); 
answered Jan 23, 2014 at 10:47
Sign up to request clarification or add additional context in comments.

Comments

2

I have an array, then I saves it to redis. After save I casts array to object through json_decode(json_encode($ar)) construction.

$redis->save($array);
$this->object = json_decode(json_encode($array));
...

Then I casts in to array again:

$ar = (array)$this->obj;

If I will do it, I can't access array properties. Solution:

$this->object = json_decode(json_encode($array), true); // get array
...
if (is_object($ar)) {
 $ar = (array)$ar;
}

Strange things...

answered Jan 23, 2014 at 10:21

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.