-1

Is there a way to access a PHP multidimensional array (specific index) dynamically?

So for example, say I want to access a value at:

$array[1]['children'][0]['children'][2]['settings']['price']

Can there be a function which returns this value by just getting index (1, 0 and 2 respectively)? and in a way that it works whether there are 3 values (1, 0 and 2) or more.

SO for example , we call function "getArrayValue()" and we can it like so:

getArrayValue('1,0,2')

this should return $array[1]['children'][0]['children'][2]['country']['city']

or in case of 2 values getArrayValue('1,0') should return $array[1]['children'][0]['country']['city']

so basically, the issue I am facing is needing help with dynamically building the query to get array value...

Or if there is a way to convert a string like $array[1]['children'][0]['country']['city'] and evaluate it to get this value from the array itself?

Another way to explain my problem:

$arrayIndex = "[1]['children'][0]";
$requiredValue = $array[1] . $arrayIndex . ['country']['city'];

//// so $requiredValue should output the same value as the below line would:
$array[1]['children'][0]['children'][2]['country']['city'];

Is there a way to achieve this?

xtrax
  • 1
  • 3
  • 1
    Basically just a variant of the "dot syntax" to array. Does this answer your question? [Convert dot syntax like "this.that.other" to multi-dimensional array in PHP](https://stackoverflow.com/questions/9635968/convert-dot-syntax-like-this-that-other-to-multi-dimensional-array-in-php) – Markus AO Feb 26 '22 at 18:03
  • also consider to do your custom function to get values from a predefined structure, why not your own `getArrayValue('1,0,2')` ? – Traian GEICU Feb 26 '22 at 18:15
  • @TraianGEICU Yes, I'm after my own custom function but the part I'm a bit confused about is dynamically accessing these values from the array, using 1, 0, 2 as variables... and while keeping the length of these variables dyncamic (so it can work with 1 2 or 3 values and so on) – xtrax Feb 26 '22 at 18:48
  • My guess is that you encounter a design issues. Hardly to figure out how you get that "long-keys" data structure. Maybe it will be much more clear to operate with objects, then long sets of keys. (just store objects in arr, access by propeties, etc ... OOP) – Traian GEICU Feb 26 '22 at 19:17

2 Answers2

4

In your case you will need something like this:

<?php
  

function getArray($i, $j, $k, $array) {
    if (isset($array[$i]['children'][$j]['children'][$k]['country']['city']))
    {
        return $array[$i]['children'][$j]['children'][$k]['country']['city'];
    }
}

$array[0]['children'][0]['children'][0]['country']['city'] = "some value";
$array[0]['children'][0]['children'][1]['country']['city'] = "another";
$array[0]['children'][1]['children'][1]['country']['city'] = "another one";
.
.
.
etc


echo getArray(0,0,0, $array) . "\n"; // output -> "some value"
echo getArray(0,0,1, $array) . "\n"; // output -> "another"
echo getArray(0,1,1, $array) . "\n"; // output -> "another one"

Another thing to keep in mind is that you have called the function passing only one parameter. And your multidimensional array needs at least three.

getArrayValue('1,0,2')

You have to take into account that you have called the function passing only one parameter. Even if there were commas. But it's actually a string.

getArrayValue(1,0,2) //not getArrayValue('1,0,2') == string 1,0,2

If you want to pass two values, you would have to put at least one if to control what you want the function to execute in that case. Something like:

  function getArray($i, $j, $k, $array) {
    if($k==null){
        if(isset($array[$i]['children'][$j]['country']['city'])){
            return $array[$i]['children'][$j]['country']['city']; //
        }
    } else {
        if(isset($array[%i]['children'][$j]['children'][$k]['country']['city'])){
            return $array[$i]['children'][$j]['children'][$k]['country']['city'];
        }
    }
}

getArray(0,0,null, $array) 
getArray(0,0,1, $array) 

For the last question you can get by using the eval() function. But I think it's not a very good idea. At least not recommended. Example:

echo ' someString ' . eval( 'echo $var = 15;' );

You can see the documentation: https://www.php.net/manual/es/function.eval.php

edit: I forgot to mention that you can also use default arguments. Like here.

<?php

$array[0]['children'][0]['children'][0]['country']['city'] = "some value";
$array[0]['children'][0]['children'][1]['country']['city'] = "another";
$array[0]['children'][1]['children'][1]['country']['city'] = "another one";

function getArray($array,$i, $j, $k = null) {
    if($k==null){
        echo 'getArray called without $k argument';
        echo "\n";
    } 
    else{
        echo 'getArray called with $k argument';
        echo "\n";
    }
   
}

getArray($array,0,0);    //here you call the function with only 3 arguments, instead of 4
getArray($array,0,0,1);

In that case $k is optional. If you omit it, the default value will be null. Also you have to take into account that A function may define default values for arguments using syntax similar to assigning a variable. The default is used only when the parameter is not specified; in particular, note that passing null does not assign the default value.

<?php
function makecoffee($type = "cappuccino"){
    return "Making a cup of $type.\n";
}
echo makecoffee();
echo makecoffee(null);
echo makecoffee("espresso");

The above example will output:

Making a cup of cappuccino.
Making a cup of .
Making a cup of espresso.

You can read more about that here: https://www.php.net/manual/en/functions.arguments.php

Dac2020
  • 165
  • 10
1

I find @Dac2020's answer to be too inflexible to be helpful to future researchers. In fact, the overly specific/niche requirements in the question does not lend this page to being very helpful for future researchers because the processing logic is tightly coupled to the array structure.

That said, I've tried to craft a function that builds best practices of checking for the existence of keys and D.R.Y. principles in the hope that future researchers will be able to easily modify it for their needs.

Inside the custom function, the first step is to split the csv into an array then interweave the static keys between the dynamic keys as dictated by the asker. In more general use cases, ALL keys would be passed into the function thus eliminating the need to prepare the array of keys.

As correctly mentioned by @MarkusAO in a comment under the question, this question is nearly a duplicate of Convert dot syntax like "this.that.other" to multi-dimensional array in PHP.

Code: (Demo)

function getValue($haystack, $indexes) {
    $indices = explode(',', $indexes);
    $finalIndex = array_pop($indices);
    $keys = [];
    foreach ($indices as $keys[]) {
        $keys[] = 'children';
    }
    array_push($keys, $finalIndex, 'country', 'city');
    //var_export($keys);

    foreach ($keys as $level => $key) {
        if (!key_exists($key, $haystack)) {
            throw new Exception(
                sprintf(
                    "Path attempt failed for [%s]. No `%s` key found on levelIndex %d",
                    implode('][', $keys),
                    $key,
                    $level
                )
            );
        }
        $haystack = $haystack[$key];
    }
    return $haystack;
}

$test = [
    [
        'children' => [
            [
                'children' => [
                    [
                        'country' => [
                            'city' => 'Paris',
                         ]
                    ],
                    [
                        'country' => [
                            'city' => 'Kyiv',
                         ]
                    ]
                ]
            ]
        ]
    ],
    [
        'children' => [
            [
                'country' => [
                    'city' => 'New York',
                ]
            ],
            [
                'country' => [
                    'city' => 'Sydney',
                ]
            ]
        ]
    ]
];

$result = [];
try {
    $result['0,0,0'] = getValue($test, '0,0,0');
    $result['1,0'] = getValue($test, '1,0');
    $result['1,0,0'] = getValue($test, '1,0,0');
} catch (Exception $e) {
    echo $e->getMessage() . "\n---\n";
}
var_export($result);

Output:

Path attempt failed for [1][children][0][children][0][country][city]. No `children` key found on levelIndex 3
---
array (
  '0,0,0' => 'Paris',
  '1,0' => 'New York',
)
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
  • I know that perhaps it was not the most optimal way, but I wanted to explain it to him, using part of his code, so that he better understands what he was asking me. I have also edited it because I forgot to mention the default arguments. Anyway, thanks for the clarification and for your answer. I imagine that as he learns he will realize that there are better options to do the same things. – Dac2020 Feb 27 '22 at 19:20