Я могу получить доступ в любом месте внутри многомерного массива с помощью ссылочного метода. И я могу изменить его ценность. Например:
$conf = array( 'type' => 'mysql', 'conf' => array( 'name' => 'mydatabase', 'user' => 'root', 'pass' => '12345', 'host' => array( '127.0.0.1', '88.67.45.123', '129.34.123.55' ), 'port' => '3306' ) ); $value = & $this->getFromArray('type.conf.host'); $value = '-- changed ---'; // result $conf = array( 'type' => 'mysql', 'conf' => array( 'name' => 'mydatabase', 'user' => 'root', 'pass' => '12345', 'host' => '-- changed ---' 'port' => '3306' ) );
НО, я не могу уничтожить этот раздел:
// normally success unset($conf['type']['conf']['host']); // fail via reference $value = & $this->getFromArray('type.conf.host'); unset($value);
с// normally success unset($conf['type']['conf']['host']); // fail via reference $value = & $this->getFromArray('type.conf.host'); unset($value);
Есть ли решение?
Хорошо, лучше я думаю. Чтобы отключиться, вы должны получить ссылку на контейнерный массив, а затем удалить элемент внутри массива;
т.е.
$value = & $this->getFromArray('type.conf'); unset $value['host'];
Ссылки не похожи на жесткие ссылки. Если вы отключите ссылку, это не приведет к отключению исходного значения.
<?php $a = 5; xdebug_debug_zval('a'); // a: (refcount=1, is_ref=0), int 5 $b = &$a; xdebug_debug_zval('a'); // a: (refcount=2, is_ref=1), int 5 xdebug_debug_zval('b'); // b: (refcount=2, is_ref=1), int 5 unset($b); xdebug_debug_zval('a'); // a: (refcount=1, is_ref=0), int 5
с<?php $a = 5; xdebug_debug_zval('a'); // a: (refcount=1, is_ref=0), int 5 $b = &$a; xdebug_debug_zval('a'); // a: (refcount=2, is_ref=1), int 5 xdebug_debug_zval('b'); // b: (refcount=2, is_ref=1), int 5 unset($b); xdebug_debug_zval('a'); // a: (refcount=1, is_ref=0), int 5
Почему бы не написать небольшой класс Config
который абстрагирует данные (массив)? Поскольку объекты всегда передаются по ссылке, вам не нужно будет обрабатывать это самостоятельно.
class Config { // ... } $config = new Config(array( 'db' => array( 'name' => 'mydatabase', 'user' => 'root', 'pass' => '12345', ) )); $config->get('db.user'); $config->set('db.user', 'newuser'); $config->unset('db.user'); //...
Создавая некоторые функции для моей структуры, думайте, что они вас останавливают.
1. Значение набора функций в массиве с использованием ссылки для навигации
– если ссылка заканчивается по имени / ключу, это имя / ключ будет равным заданному значению
– если ссылка заканчивается разделителем, фамилия / ключ будет массивом с заданным значением
function array_reference_set($input_arr=array(),$reference='',$delimiter='->',$set_var=''){ switch ($reference){ case (is_string($reference)): $reference = array_reverse(explode($delimiter, $reference),true); break; case (!is_array($reference)): return $input_arr; } $key = array_pop($reference); if (count($reference)<1){ if($key!=''){ $input_arr[$key] = $set_var; }elseif (!is_array($input_arr) && $key==''){ $input_arr = array($set_var); }elseif ($key==''){ $input_arr[] = $set_var; } }else{ if (!is_array($input_arr)){ $input_arr = array($key=>array()); } if (isset($input_arr[$key])){ $input_arr[$key] = $this->array_reference_set($input_arr[$key],$reference,$delimiter,$set_var); }else{ $input_arr[$key] = $this->array_reference_set(array(),$reference,$delimiter,$set_var); } } return $input_arr; } $arr = array_reference_set(array(),'a->b->c','->','test'); //equal $arr = array('a'=>array('b'=>array('c'=>'test')));//or $arr['a']['b']['c'] = 'test'; $arr = array_reference_set(array(),'a->b->c->','->','test'); //equal $arr = array('a'=>array('b'=>array('c'=>array('test'))));//or $arr['a']['b']['c'][] = 'test';
2. Функция set unset value из массива с использованием ссылки
– если ссылка заканчивается, это разделитель, то будет отменено varible с именем / ключом для разделителя
– один момент использования этой функции: вам нужен массив обновлений, возвращенный результат функции (в конце примера кода)
function array_reference_unset($input_arr=array(),$reference='',$delimiter='->'){ switch ($reference){ case (is_string($reference)): $reference = array_reverse(explode($delimiter, $reference),true); break; case (!is_array($reference)): return $input_arr; } $key = array_pop($reference); if (count($reference)<1 && is_string($key)){ if ($key!=''){ unset($input_arr[$key]); }else{ return false; } }else{ if (isset($input_arr[$key])){ $ret = $this->array_reference_unset($input_arr[$key],$reference,$delimiter); if ($ret!==false){ $input_arr[$key] = $ret; }else{ unset ($input_arr[$key]); } } } return $input_arr; } $arr = array('a'=>array('b'=>array('c'=>'test')));// test subject $arr = array_reference_unset($arr,'a->b->c','->');//and $arr = array_reference_unset($arr,'a->b->c->','->'); //equal unset($arr['a']['b']['c']);
сfunction array_reference_unset($input_arr=array(),$reference='',$delimiter='->'){ switch ($reference){ case (is_string($reference)): $reference = array_reverse(explode($delimiter, $reference),true); break; case (!is_array($reference)): return $input_arr; } $key = array_pop($reference); if (count($reference)<1 && is_string($key)){ if ($key!=''){ unset($input_arr[$key]); }else{ return false; } }else{ if (isset($input_arr[$key])){ $ret = $this->array_reference_unset($input_arr[$key],$reference,$delimiter); if ($ret!==false){ $input_arr[$key] = $ret; }else{ unset ($input_arr[$key]); } } } return $input_arr; } $arr = array('a'=>array('b'=>array('c'=>'test')));// test subject $arr = array_reference_unset($arr,'a->b->c','->');//and $arr = array_reference_unset($arr,'a->b->c->','->'); //equal unset($arr['a']['b']['c']);
ps извините за мой чистый английский
Вот моя функция для отключения вложенных ключей
public function unsetKey(string $dotSeparatedKey) { $keys = explode('.', $dotSeparatedKey); $pointer = &$this->data; $current = false; // just to make code sniffer happy // we traverse all but the last key while (($current = array_shift($keys)) && (count($keys) > 0)) { // if some key is missing all the subkeys will be already unset if (!array_key_exists($current, $pointer)) { // is already unset somewhere along the way return; } // set pointer to new, deeper level // called for all but last key $pointer = &$pointer[$current]; } // handles empty input string if ($current) { // we finally unset what we wanted unset($pointer[$current]); } }
сpublic function unsetKey(string $dotSeparatedKey) { $keys = explode('.', $dotSeparatedKey); $pointer = &$this->data; $current = false; // just to make code sniffer happy // we traverse all but the last key while (($current = array_shift($keys)) && (count($keys) > 0)) { // if some key is missing all the subkeys will be already unset if (!array_key_exists($current, $pointer)) { // is already unset somewhere along the way return; } // set pointer to new, deeper level // called for all but last key $pointer = &$pointer[$current]; } // handles empty input string if ($current) { // we finally unset what we wanted unset($pointer[$current]); } }