Question

I'm just wondering about how variable variables that point to Arrays handle. Take the code below:

$a = new stdClass(); 
$a->b = array('start' => 2); 
$c = 'b'; 
$d = 'start';
print $a->$c; // => Array
print $a->$c['start']; // => Array
print $a->$c[0]; // => Array
print $a->$c[0][0]; //=> PHP Fatal error:  Cannot use string offset as an array in php shell code on line 1

The first print I expect, the second one I don't, or the 3rd. The 4th is expected after realizing that the evaluation of $a->$c is apparently a string. But then why does this work:

$t = $a->$c;
print $t['start']; //=> 2

I'm asking more because I'm curious than I need to know how to nicely do

$e = 'start';
$a->$c[$e]

Anyone know why I can't index directly into the array returned by the variable variable usage?

Was it helpful?

Solution

It comes down to order of operations and how PHP type juggles. Hint: var_dump is your friend, echo always casts to a string so it is the worst operation for analyzing variable values, esp in debug settings.

Consider the following:

var_dump($a->$c); // array (size=1) / 'start' => int 2
var_dump($a->$c['start']); // array (size=1) / 'start' => int 2
var_dump($a->b['start']); // int 2
var_dump($c['start']); // string 'b' (length=1)

The key here is how PHP interprets the part of $c['start'] (include $c[0] here as well). $c is the string 'b', and when attempting to get the 'start' index of string 'b' this simply returns the first character in the string, which happens to simply be the only letter (b) in the string. You can test this out by using $c = 'bcdefg'; - it'll yield the same result (in this specific case). Also, $c['bogus'] will yield the exact same thing as $c['start']; food for thought, and make sure you do the required reading I linked to.

So with this in mind (knowing that $c['start'] reluctantly returns 'b'), the expression $a->$c['start'] is interpreted at $a->b. That is, the order is $a->($c['start']) and not ($a->$c)['start'].

Unfortunately you can't use () nor {} to steer the parser (PHP SCREAMs), so you won't be able to accomplish what you want in a single line. The following will work:

$e = 'start';
$interim = $a->$c;
echo $interim[$e];

Alternatively, you can cast your arrays as objects (if you have the luxury):

$a->$c = (object) $a->$c; // mutate
var_dump($a->$c->$e);

$interim = (object) $a->$c; // clone
var_dump($interim->$e);

...by the way, referring back up to $c['start'] and $c[0], in regards to $c[0][0] you simply can't do this because $c[0] is the character b in string 'b'; when access the character/byte b it will not have a property of [0].

OTHER TIPS

$a->$c[0]; is actually equal to: array('start' => 0)

so when you did:

print $a->$c[0][0];

You are trying to load an array element from $a->$c[0] at index 0 which does not exists.

however, this will work:

print $a->$c[0]['start'];

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top