I want to create a nested array key with a single variable. I know how to do it if I split it up into separate keys, but not with specifying the nested key as a single string or something like it.
I have the array keys as strings already. I have a function that must place an incoming string into the right place in an array, but it only accepts two parameters - the key and the value. (There is a corresponding function that gets the appropriate array values instead of placing them.) I can edit the function, but I already have a massive amount of keys-as-strings. I know I could explode / regex the string into separate variables as needed in the function, but this would be liable to error as the strings themselves could be escaped, contain strange characters, and so on. I’m trying very hard to avoid an explode / regex solution.
Edit: If you can tell me how to do it, even if you think it doesn’t suit this use case, I very much still need to know for other use cases.
I am not aware of anything builtin to php that will allow you to do this. But there a Symfony component called PropertyAccessor with this sort of functionality.
The code would look like:
use Symfony\Component\PropertyAccess\PropertyAccess;
$accessor = PropertyAccess::createPropertyAccessor();
$accessor->setValue($array,'[houses][ocean_view][state]';
I am not aware of a native function to do that, but you could write your own. :-) E.g. this function would take two arrays, the array to access and an array of keys, and recursively walk down the array (if nested) to eventually return a reference (if desired) to the match, like
/**
* Return the reference to an element/subarray
* of an array, specified by a key array
*
* @param array &$array Array to access by reference
* @param mixed $keys Array of the keys
* @return mixed Reference to the match
*/
function &array_access(&$array, $keys) {
// If there are keys left to walk down
// a nested array
if ($keys) {
$key = array_shift($keys);
// Get and return the reference to the
// subarray with the current key
$sub = &array_access(
$array[$key],
$keys
);
return $sub;
} else {
// Return the match
return $array;
}
}
// Usage
$array = [];
$keys =['houses', 'ocean_view', 'state'];
// Here we're accessing the array match
// by reference
$reference = &array_access($array, $keys);
$reference = 'Oregon';
// But we might also just return the value
$value = array_access($array, $keys);
echo $value;
$value = 'Ibiza';
print_r($array);
If the format of $keys is fixed as a string like above, you might parse it to an array like e.g.
You might also incorporate that functionality right within the access function, like
/**
* Return the reference to an element/subarray
* of an array, specified by a key array or string
*
* @param array &$array Array to access by reference
* @param mixed $keys Array of the keys, or a string
* representation of how you'd normally
* access $array
* @return mixed Reference to the match
*/
function &array_access(&$array, $keys) {
// Check if $keys is a string
if (is_string($keys)) {
// Parse it to an array
$keys = explode(
'][',
preg_replace(
'/^\[|\]$/',
'',
$keys
)
);
}
// etc...
}
Thanks ahundiak - I did not know that symfony component existed. It is a little heavy duty for what I need, but it looks like I could make it fit. The example you provided helped.
Thanks m3g4p0p - you went above and beyond with that example code (even with doc blocks!). I learned a lot. I will probably implement something very close to what you’ve done, even though I was trying to avoid regex and exploding. If I can’t make it work the way I want, I will fall back to the symfony component.
In your code, you use & in front of the function name ( &array_access ) when declaring the function, and also when calling it recursively within the function. I am not familiar with this usage - is this passing the function itself by reference or is it only a naming convention you use to indicate the function takes a value by reference?
Both are necessary here: the & in front of the function name in the declaration means that the function will return by reference, and the one in front of the call is for binding this reference to a variable – thus allowing us to return the reference up the recursion.