I've to implement a setter in PHP, that allows me to specify the key, or sub key, of an array (the target), passing the name as a dot-separated-keys value.
Given the following code:
$arr = array('a' => 1, 'b' => array( 'y' => 2, 'x' => array('z' => 5, 'w' => 'abc') ), 'c' => null); $key = 'b.x.z'; $path = explode('.', $key);
From the value of $key
I want to reach the value 5 of $arr['b']['x']['z']
.
Now, given a variable value of $key
and a different $arr
value (with different deepness).
$key
?For the getter get()
I wrote this code:
public static function get($name, $default = null) { $setting_path = explode('.', $name); $val = $this->settings; foreach ($setting_path as $key) { if(array_key_exists($key, $val)) { $val = $val[$key]; } else { $val = $default; break; } } return $val; }
To write a setter is more difficult because I succeed in reaching the right element (from the $key
), but I am not able to set the value in the original array and I don't know how to specify the keys all at once.
Should I use some kind of backtracking? Or can I avoid it?
Assuming $path
is already an array via explode
(or add to the function), then you can use references. You need to add in some error checking in case of invalid $path
etc. (think isset
):
$key = 'b.x.z'; $path = explode('.', $key);
function get($path, $array) { //$path = explode('.', $path); //if needed $temp =& $array; foreach($path as $key) { $temp =& $temp[$key]; } return $temp; } $value = get($path, $arr); //returns NULL if the path doesn't exist
This combination will set a value in an existing array or create the array if you pass one that has not yet been defined. Make sure to define $array
to be passed by reference &$array
:
function set($path, &$array=array(), $value=null) { //$path = explode('.', $path); //if needed $temp =& $array; foreach($path as $key) { $temp =& $temp[$key]; } $temp = $value; } set($path, $arr); //or set($path, $arr, 'some value');
This will unset
the final key in the path:
function unsetter($path, &$array) { //$path = explode('.', $path); //if needed $temp =& $array; foreach($path as $key) { if(!is_array($temp[$key])) { unset($temp[$key]); } else { $temp =& $temp[$key]; } } } unsetter($path, $arr);
*The original answer had some limited functions that I will leave in case they are of use to someone:
Setter
Make sure to define $array
to be passed by reference &$array
:
function set(&$array, $path, $value) { //$path = explode('.', $path); //if needed $temp =& $array; foreach($path as $key) { $temp =& $temp[$key]; } $temp = $value; } set($arr, $path, 'some value');
Or if you want to return the updated array (because I'm bored):
function set($array, $path, $value) { //$path = explode('.', $path); //if needed $temp =& $array; foreach($path as $key) { $temp =& $temp[$key]; } $temp = $value; return $array; } $arr = set($arr, $path, 'some value');
Creator
If you wan't to create the array and optionally set the value:
function create($path, $value=null) { //$path = explode('.', $path); //if needed foreach(array_reverse($path) as $key) { $value = array($key => $value); } return $value; } $arr = create($path); //or $arr = create($path, 'some value');
For Fun
Constructs and evaluates something like $array['b']['x']['z']
given a string b.x.z
:
function get($array, $path) { //$path = explode('.', $path); //if needed $path = "['" . implode("']['", $path) . "']"; eval("\$result = \$array{$path};"); return $result; }
Sets something like $array['b']['x']['z'] = 'some value';
:
function set(&$array, $path, $value) { //$path = explode('.', $path); //if needed $path = "['" . implode("']['", $path) . "']"; eval("\$array{$path} = $value;"); }
Unsets something like $array['b']['x']['z']
:
function unsetter(&$array, $path) { //$path = explode('.', $path); //if needed $path = "['" . implode("']['", $path) . "']"; eval("unset(\$array{$path});"); }
I have solution for you not in the pure PHP, but using ouzo goodies concretely Arrays::getNestedValue method:
$arr = array('a' => 1, 'b' => array( 'y' => 2, 'x' => array('z' => 5, 'w' => 'abc') ), 'c' => null); $key = 'b.x.z'; $path = explode('.', $key); print_r(Arrays::getNestedValue($arr, $path));
Similarly if you need to set nested value you can use Arrays::setNestedValue method.
$arr = array('a' => 1, 'b' => array( 'y' => 2, 'x' => array('z' => 5, 'w' => 'abc') ), 'c' => null); Arrays::setNestedValue($arr, array('d', 'e', 'f'), 'value'); print_r($arr);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With