Заглянув в документацию Коханы, я нашел эту полезную функцию, которую они используют для получения значений из многомерного массива с использованием точечной нотации, например:
$foo = array('bar' => array('color' => 'green', 'size' => 'M')); $value = path($foo, 'bar.color', NULL , '.'); // $value now is 'green'
Мне интересно, есть ли способ установить значение массива таким же образом:
set_value($foo, 'bar.color', 'black');
Единственный способ, которым я нашел это, – перестроить нотацию массива ($ array ['bar'] ['color']), а затем установить значение .. с помощью eval
.
Любая идея избежать eval?
function set_val(array &$arr, $path,$val) { $loc = &$arr; foreach(explode('.', $path) as $step) { $loc = &$loc[$step]; } return $loc = $val; }
Конечно, это возможно.
function set_value(&$root, $compositeKey, $value) { $keys = explode('.', $compositeKey); while(count($keys) > 1) { $key = array_shift($keys); if(!isset($root[$key])) { $root[$key] = array(); } $root = &$root[$key]; } $key = reset($keys); $root[$key] = $value; }
$foo = array(); set_value($foo, 'bar.color', 'black'); print_r($foo);
Выходы
Array ( [bar] => Array ( [color] => black ) )
Смотрите в действии .
Посмотрите https://gist.github.com/elfet/4713488
$dn = new DotNotation(['bar'=>['baz'=>['foo'=>true]]]); $value = $dn->get('bar.baz.foo'); // $value == true $dn->set('bar.baz.foo', false); // ['foo'=>false] $dn->add('bar.baz', ['boo'=>true]); // ['foo'=>false,'boo'=>true]
Таким образом вы можете установить следующие значения более одного раза для одной и той же переменной.
Вы можете сделать эти два пути (по статической переменной и ссылочной переменной):
<?php function static_dot_notation($string, $value) { static $return; $token = strtok($string, '.'); $ref =& $return; while($token !== false) { $ref =& $ref[$token]; $token = strtok('.'); } $ref = $value; return $return; } $test = static_dot_notation('A.1', 'A ONE'); $test = static_dot_notation('A.2', 'A TWO'); $test = static_dot_notation('B.C1', 'C ONE'); $test = static_dot_notation('B.C2', 'C TWO'); $test = static_dot_notation('BCD', 'D ONE'); var_export($test); /** array ( 'A' => array ( 1 => 'A ONE', 2 => 'A TWO', ), 'B' => array ( 'C1' => 'C ONE', 'C2' => 'C TWO', 'C' => array ( 'D' => 'D ONE', ), ), */ function reference_dot_notation($string, $value, &$array) { static $return; $token = strtok($string, '.'); $ref =& $return; while($token !== false) { $ref =& $ref[$token]; $token = strtok('.'); } $ref = $value; $array = $return; } reference_dot_notation('person.name', 'Wallace', $test2); reference_dot_notation('person.lastname', 'Maxters', $test2); var_export($test2); /** array ( 'person' => array ( 'name' => 'Wallace', 'lastname' => 'Maxters', ), ) */
Для этого я создал небольшой класс!
http://github.com/projectmeta/Stingray
$stingray = new StingRay(); //To Get value $stingray->get($array, 'this.that.someother'): //To Set value $stingray->get($array, 'this.that.someother', $newValue):
Обновленный ответ @hair смолы для удовлетворения:
Когда подпуть не является массивом
function set_val(array &$arr, $path,$val) { $loc = &$arr; $path = explode('.', $path); foreach($path as $step) { if ( ! isset($loc[$step]) OR ! is_array($loc[$step])) $loc = &$loc[$step]; } return $loc = $val; }