6

In a normal array you can select this way

$key='example';
echo $array[$key];

How about in a multidimensional?

$keys='example[secondDimension][thirdDimension]';
echo $array[$keys];

What's the proper way to go about this?

Button 108
  • 349
  • 1
  • 8

6 Answers6

2

i think this solution is good.

note that you have to wrap all keys with "[" and "]".

$array = array(
    'example' => array(
        'secondDimension' => array(
            'thirdDimension' => 'Hello from 3rd dimension',
        )
    ),
);

function array_get_value_from_plain_keys($array, $keys)
{
    $result;

    $keys = str_replace(array('[', ']'), array("['", "']"), $keys); // wrapping with "'" (single qoutes)

    eval('$result = $array' . $keys . ';');

    return $result;
}

$keys = '[example][secondDimension][thirdDimension]'; // wrap 1st key with "[" and "]"
echo array_get_value_from_plain_keys($array, $keys);

Learn more about eval() function

if you also want to check if the value is defined or not then you can use this function

function array_check_is_value_set_from_plain_keys($array, $keys)
{
    $result;

    $keys = str_replace(array('[', ']'), array("['", "']"), $keys); // wrapping with "'" (single qoutes)

    eval('$result = isset($array' . $keys . ');');

    return $result;
}

Giving a better name to that function will be appreciated ^^

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Abdullah Mallik
  • 740
  • 8
  • 21
  • 2
    Using `eval()` is generally a bad idea, especially if there is any possibility of user input. – Jeremy Harris Dec 09 '16 at 18:46
  • 1
    Actually, this is very close to what I was looking for... After taking the time to really pay attention to what you did. I actually had tried doing it with eval. You nailed it. Thanks! And, yes, Jeremy, I'm aware of the security concerns of eval. IMO, it should be safe as long as you are sure no user input could find it's way into the mix. Some escaping could also be added to the function to be extra sure, but best case is to keep the user input far away. Definitely something for me to keep in mind. Thanks to you as well. – Button 108 Dec 12 '16 at 03:43
  • Using eval() is fine as long as there is no possibility of code injection via malicious user input. – siliconrockstar May 18 '23 at 18:37
0

Here is a solution without using eval:

$array = [
    'example' => [
        'secondDimension' => [
            'thirdDimension' => 'Hello from 3rd dimension',
        ],
    ],
];

$keys = '[example][secondDimension][thirdDimension]';

function get_array_value( $array, $keys ) {
    $keys = explode( '][', trim( $keys, '[]' ) );

    return get_recursive_array_value( $array, $keys );
}

function get_recursive_array_value( $array, $keys ) {
    if ( ! isset( $array[ $keys[0] ] ) ) {
        return null;
    };
    $res = $array[ $keys[0] ];
    if ( count( $keys ) > 1 ) {
        array_shift( $keys );

        return get_recursive_array_value( $res, $keys );
    } else {
        return $res;
    }
}

echo get_array_value( $array, $keys );
Sergiy Zaharchenko
  • 1,490
  • 1
  • 12
  • 11
0

Want you to use the $b array to follow the nested keys of the $a array and get the value in $c ?

<?php
$a = [ 'key_1' => [ 'key_2' => [ 'key_3' => 'value', ], ], ] ;
$b = ['key_1', 'key_2', 'key_3', ] ;
if ($b)
{
    $c = $a ; // $a is not copied (copy-on-write)
    foreach($b as $k)
        if (isset($c[$k]))
            $c = $c[$k] ;
        else
        {
            unset($c);
            break;
        }
    var_dump($c);
}
/*
output :
    string(5) "value"
*/

or do you want to generate the $b array for an arbitrary formed string and get $c as a reference ?

<?php
$a = [ 'key_1' => [ 'key_2' => [ 'key_3' => 'value', ], ], ] ;
$b = '[key_1][key_2][key_3]';
if ($b !== '')
{
    $b = explode('][', trim($b, '[]'));
    $c = &$a ;
    foreach($b as $k)
        if (isset($c[$k]))
            $c = &$c[$k] ;
        else
        {
            unset($c);
            break;
        }
}
var_dump($c);
$c = 'new val' ;
unset($c);
var_dump($a['key_1']['key_2']['key_3']);
/*
output :
    string(5) "value"
    string(7) "new val"
*/
0

Simplified example using eval() I wrote to extract phone numbers from an array of Shopify customer data:

    // this is weird but whatever
    $arrayPaths = array(
        '[\'phone\']',
        '[\'addresses\'][0][\'phone\']',
        '[\'addresses\'][1][\'phone\']'
        );
    
    foreach ($arrayPaths as $path) {
        
        // hack to store/access multidimentional array keys as array, sets 
        // a variable named $phoneNumber
        $code = '$phoneNumber = $dataArray' . $path . ';';
        eval($code);
        var_dump($phoneNumber);
        
    }

DISCLAIMER FOR THE EVAL() POLICE: don't use eval() if there is any chance of code injection via malicious user input. I'm running this as part of a one-time data migration script on a VM on my local computer, the only network interactions are calls out to the Shopify API.

siliconrockstar
  • 3,554
  • 36
  • 33
  • Whenever `eval()` seems appropriate, that is a string indicator that a rethink and/or a refactor is in order. – mickmackusa Apr 13 '23 at 07:46
  • @mickmackusa in this case, it's a workaround for a feature gap in the language, in a single use data migration script running in a VM on my local machine, with a 0% chance of external code injection. A refactor would be a waste of time. – siliconrockstar May 18 '23 at 18:36
0

The most elegant way to solve this problem, is to make a recursive function that gets the value. Here is my suggestion:

/**
 * Get value of given path of keys for a given multidimentional array in a recursive way.
 * @param array $array   A multidimentional array
 * @param array $key     A path of keys, example [1, 'name']
 * @param mixed $default What to return if path of keys does not exist in given array
 * @return mixed The found value, or the default value (can be any data type)
 */
function recursiveGetValue(array $array, array $key, $default=null) {
    $currentKey = current($key);
    if (!array_key_exists($currentKey, $array)) {
        return $default;
    }
    else if (count($key)==1) {
        return $array[$currentKey];
    }
    else {
        $restArray = $array[$currentKey];
        $restKey = array_slice($key, 1);
        return recursiveGetValue($restArray, $restKey, $default);
    }
}

$array = [
    'one'  =>['name'=>'Per', 'age'=>10],
    'two'  =>['name'=>'Pål', 'age'=>20],
    'three'=>['name'=>'Jan', 'age'=>15],
];

echo(recursiveGetValue($array, ['two', 'age']));

paalg
  • 11
  • 2
  • Please do not use unnecessary parentheses with `echo`. Please write `elseif` as a single word for PSR-12 compliance. – mickmackusa Apr 13 '23 at 07:48
-2

You have to use a separate variable for each dimension of the array. A common pattern you see with multidimensional arrays where you need to do something with the 2nd dimension is something like this:

$pets = [
    'dog' => ['Jack', 'Fido', 'Woofie'],
    'cat' => ['Muggles', 'Snowball', 'Kitty'],
];

// Loop through keys in first dimension
foreach ($pets as $type => $names) {

    foreach ($names as $index => $name) {

        // And do something with second dimension using the variable
        // you've gained access to in the foreach
        $pets[$type][$index] = strtoupper($name);

    }

}
Jeremy Harris
  • 24,318
  • 13
  • 79
  • 133
  • 1
    Thanks for your comment. This is typically how I deal with multi-dimensional arrays. In this case, I was looking for something that could go to extreme and variable depths with low-cost... particularly something built in. Anyway, thanks! – Button 108 Dec 12 '16 at 03:39