2

Let's say I have the following multi-dimensional array:

$fruits['apple']['name'] = 'macintosh';

Is there any way of referencing the entire key path in a single variable?

I would like to somehow do the following:

$path = "['apple']['name']";
echo $fruits[$path];

//output would be "macintosh"
Allen Liu
  • 3,948
  • 8
  • 35
  • 47
  • &references comes to my mind.. –  Jun 06 '12 at 20:29
  • @vizvi Can you expand a bit on that? Thanks. – Allen Liu Jun 06 '12 at 20:30
  • you could call: $fruits2 = &fruits['apple']; echo $fruits2['name']; would give "macintosh" –  Jun 06 '12 at 20:31
  • 1
    maybe interesting to you: http://stackoverflow.com/questions/8376602/flatten-multidimensional-associative-array-to-one-one-dimensional-array-of-refer if you would like `$fruits['apple/name']` to be valid – goat Jun 06 '12 at 20:34
  • You could always use classes instead of arrays. – Jared Jun 06 '12 at 20:35
  • see this too: http://stackoverflow.com/questions/10424335/php-convert-multidimensional-array-to-2d-array-with-dot-notation-keys – goat Jun 06 '12 at 20:39

5 Answers5

3

Is there any way of referencing the entire key path in a single variable?

1) In a way like this: $fruits[$variable], the answer is no, there isn't.

Of course, there are several ways you can split a single $variable in two or more, and then use its parts separetely ($fruits[$part1][$part2])

This is a generic solution:

function get_path($array, $path)
{
    $value = $array;
    $parts = explode("']['", trim($path, "[']"));
    foreach($parts as $key)
    {
        $value = $value[$key];
    }
    return $value;
}

$fruits['apple']['name'] = 'macintosh';
$path = "['apple']['name']";
echo get_path($fruits, $path);

// output = 'macintosh'

2) As also pointed, you could use "eval", which is not recommended:

$fruits['apple']['name'] = 'macintosh';
$path = "['apple']['name']";
eval('echo $fruits' . $path . ';');

// output = 'macintosh'

3) Finally, if you want to access an element of the array using a reference variable, then simply:

$fruits['apple']['name'] = 'macintosh';
$path &= $fruits['apple']['name'];
echo $path;  // output = 'macintosh'

$path = 'MSX';
echo $fruits['apple']['name'];  // output = 'MSX'
J. Bruni
  • 20,322
  • 12
  • 75
  • 92
1

There is obviously the horrible, never-to-be-used approach: eval()

But if you really want to do something like this, I would prefer something like this approach:

function &array_value_by_address (&$array, $address, $addressSeparator = '/') {
  $parts = explode($addressSeparator, $address);
  $thisLevel = array_shift($parts);
  if (isset($array[$thisLevel])) {
    if ($parts) {
      $ref = &array_value_by_address($array[$thisLevel], implode($addressSeparator, $parts));
      return $ref;
    } else {
      return $array[$thisLevel];
    }
  }
}

Because of the references in the function declaration, it's also possible to catch the return value in a variable and use it to modify the source array. This is optional - if you omit the & prefix at call time the caught value will simply be a copu and not a reference.

The caveat though - the function will return NULL if the "address" within the array does not exist, but there is no way to distinguish between this situation and a NULL value stored within the array.

See it working

DaveRandom
  • 87,921
  • 11
  • 154
  • 174
1

J Brun's #3 answer is your best bet, however, his answer is not correct as he has demonstrated the bitwise-AND operator (&=) and not the referential assignment. This is the corrected code:

$fruits['apple'] = array( 'name' => 'macintosh' );

$path = &$fruits['apple']['name'];

echo $path; // outputs 'macintosh';
KoZm0kNoT
  • 462
  • 6
  • 9
0

References might be what you need:

$path = &$fruits['apple']['name'];

Now every time you would access $path, it's the value of $fruits['apple']['name'] that will be used (or changed, etc.).

Samy Dindane
  • 17,900
  • 3
  • 40
  • 50
0

What you want to do is not directly possible - it would be ambigous if variables are chained.

You will need to write an accessor function such as

define('SEPARATOR','|');

function getElement($array,$path) {
  $path=explode(SEPARATOR,$path);
  $out=&$array;
  foreach ($path as $step) {
    if (!isset($out[$step])) return null;
    $out=$out[$step];
  }
  return $out;
}

$path="apple|name";
echo getElement($fruits,$path);
Eugen Rieck
  • 64,175
  • 10
  • 70
  • 92