2

I'm trying to retrieve an item from a multi-dimensional array through a string that describes the path into the array (like first.second.third).

I've chosen the approach as shown here (also available on ideone):

<?php
    // The path into the array
    $GET_VARIABLE = "a.b.c";
    // Some example data
    $GLOBALS["a"]= array("b"=>array("c"=>"foo"));

    // Construct an accessor into the array
    $variablePath = explode( ".", $GET_VARIABLE );
    $accessor = implode( "' ][ '", $variablePath );
    $variable = "\$GLOBALS[ '". $accessor . "' ]";

    // Print the value for debugging purposes (this works fine)
    echo $GLOBALS["a"]["b"]["c"] . "\n";
    // Try to evaluate the accessor (this will fail)
    echo $$variable;
?>

When I run the script, it will print two lines:

foo
PHP Notice:  Undefined variable: $GLOBALS[ 'a' ][ 'b' ][ 'c' ] in ...

So, why does this not evaluate properly?

Oliver Salzburg
  • 21,652
  • 20
  • 93
  • 138

4 Answers4

5

I think the $$ notation only accepts a variable name (ie. the name of a variable). You are actually trying to read a variable named "$GLOBALS[ 'a' ][ 'b' ][ 'c' ]", which does not exist.

As an alternative ($GET_VARIABLE seems to be your input string), you could try this:

$path = explode('.', $GET_VARIABLE);
echo $GLOBALS[$path[0]][$path[1]][path[2]];

Wrap this in a suitable loop to make it more dynamic; it seems to be trivial.

RandomSeed
  • 29,301
  • 6
  • 52
  • 87
2

It looks like PHP is treating your entire string like a variable name, and not as an array.

You could try using the following approach instead, as it would also probably be simpler.

<?php
    // The path into the array
    $GET_VARIABLE = "a.b.c";
    // Some example data
    $GLOBALS["a"]= array("b"=>array("c"=>"foo"));

    // Construct an accessor into the array
    $variablePath = explode( ".", $GET_VARIABLE );
    //$accessor = implode( "' ][ '", $variablePath );
    //$variable = "\$GLOBALS[ '". $accessor . "' ]";

    // Print the value for debugging purposes (this works fine)
    echo $GLOBALS["a"]["b"]["c"] . "\n";
    // Try to evaluate the accessor (this will fail)
    echo $GLOBALS[$variablePath[0]][$variablePath[1]][$variablePath[2]];
?>
koerbcm
  • 340
  • 1
  • 2
  • 13
  • The number of elements in the the path would be variable though, which is why I was looking for this evaluation in the first place. – Oliver Salzburg Jul 09 '13 at 14:57
1

Here's some code I wrote to access $_SESSION variables via dot notation. You should be able to translate it fairly easily.

<?php
$key = "a.b.c";    
$key_bits = explode(".", $key);

$cursor = $_SESSION;

foreach ($key_bits as $bit)
{
    if (isset($cursor[$bit]))
    {
        $cursor = $cursor[$bit];
    }
    else
    {
        return false;
    }
}

return $cursor;
Jim Rubenstein
  • 6,836
  • 4
  • 36
  • 54
1

Here's one more solution using a helper function:

function GetValue($path, $scope = false){
    $result = !empty($scope) ? $scope : $GLOBALS;

    // make notation uniform
    $path = preg_replace('/\[([^\]]+)\]/', '.$1', $path); // arrays
    $path = str_replace('->', '.', $path); // object properties

    foreach (explode('.', $path) as $part){
        if (is_array($result) && array_key_exists($part, $result)){
            $result = $result[$part];
        } else if (is_object($result) && property_exists($result, $part)){
            $result = $result->$part;
        } else {
            return false; // erroneous
        }
    }
    return $result;
}

And example usage:

// Some example data
$GLOBALS["a"] = array(
  'b' => array(
    'c' => 'foo',
    'd' => 'bar',
   ),
   'e' => (object)array(
     'f' => 'foo',
     'g' => 'bar'
   )
);
$bar = array(
  'a' => $GLOBALS['a']
);

echo $GLOBALS['a']['b']['c'] . "\n"; // original

// $GLOBALS['a']['b']['c']
echo GetValue('a.b.c')       . "\n"; // traditional usage
// $GLOBALS['a']['b']['c']
echo GetValue('a[b][c]')     . "\n"; // different notation
// $bar['a']['b']['c']
echo GetValue('a.b.c', $bar) . "\n"; // changing root object
// $GLOBALS['a']['e']->f
echo GetValue('a[e]->f')     . "\n"; // object notation
Brad Christie
  • 100,477
  • 16
  • 156
  • 200