I'm trying to access a nested array (an array which contains arrays which contains arrays …)
I need to get the last value, given the array and the path of keys.
Given foo and a…z i need to get
foo[a][b][c]…[x][y][z]
I'm wondering if there is any more elegant way than this?
function getValueRecursive(array $array, string ...$identifyer){
$value = $array;
foreach($identifyer as $key){
if(!key_exists($key, $value))
return NULL;
$value = $value[$key];
}
return $value;
}
$foo = [
'a' => [
'b' => [
'c' => "Hallo Welt!"
]
]
];
echo getValueRecursive($foo, 'a', 'b', 'c'); // Returns "Hallo Welt!"
<?php
$foo = [
'a' => [
'b' => [
'c' => "Hallo Welt!"
]
]
];
$result=array();
array_walk_recursive($foo, function($value,$key) use (&$result){
$result[]=$value;
});
print_r($result[0]);
Or
<?php
ini_set("display_errors", 1);
$foo = [
'a' => [
'b' => [
'c' => "Hallo Welt!"
]
]
];
echo getValueOfArray($foo,"a","b","c");
function getValueOfArray($array)
{
$args=func_get_args();
unset($args[0]);
$string="";
foreach($args as $value)
{
$string.="['$value']";
}
eval('if(isset($array'.$string.'))
{
$result= $array'.$string.';
}');
return $result;
}
Output:
Hallo Welt!
Some time ago I wrote arrays library that uses ArrayAccess interface to achieve such operations. It allows not only retrieve but also store and delete values.
For all offset*() methods I used higher order method walkThroughOffsets:
protected function walkThroughOffsets(
&$array,
Callable $baseCaseAction,
Callable $offsetNotExistsAction
) {
$offset = array_shift($this->offsets);
if (is_scalar($offset) && isset($array[$offset])) {
if (empty($this->offsets)) {
return $baseCaseAction($array, $offset);
}
return $this->walkThroughOffsets(
$array[$offset],
$baseCaseAction,
$offsetNotExistsAction
);
}
return $offsetNotExistsAction($array, $offset);
}
Having this method you can implement offsetGet method (that is called when you try to access array value) like this:
public function offsetGet($offset)
{
$this->setOffsets($offset);
return $this->walkThroughOffsets(
$this->container,
function ($array, $offset) {
return $array[$offset];
},
$this->undefinedOffsetAction
);
}
Then you can get values as simple as with usual array:
$array = new CompositeKeyArray([
'foo' => [
'bar' => 'baz'
]
]);
var_dump($array[['foo', 'bar']]); // => string(3) "baz"
var_dump($array[['foo', 'quux']]); // => PHP Fatal error: Uncaught UndefinedOffsetException: Undefined offset quux.
Your approach is very similar to what I would recommend. I suppose this is basically a "stacking" technique versus making conditional/repetitive calls of the custom function. I do find your approach to be sufficiently elegant.
Adjustments:
null), so it is inappropriate to arbitrarily return null when an invalid key path is provided. Instead throw an exception so that a differentiation of outcomes can be made where ever the function is called from.Code: (Demo) (Fringe Case)
function getValueRecursive(array $array, ...$keys) {
foreach ($keys as $key) {
if (!key_exists($key, $array)) {
throw new Exception('key path invalid');
}
$array = $array[$key];
}
return $array;
}
$foo = [
'a' => [
'b' => [
'c' => "Hallo Welt!"
]
]
];
try {
var_export(getValueRecursive($foo, 'a', 'b', 'c'));
echo "\n---\n";
var_export(getValueRecursive($foo, 'a', 'b'));
echo "\n---\n";
var_export(getValueRecursive($foo, 0, 'b', 'c'));
} catch (Exception $e) {
echo 'Caught exception: ' . $e->getMessage();
}
Output:
'Hallo Welt!'
---
array (
'c' => 'Hallo Welt!',
)
---
Caught exception: key path invalid