сбросить элемент массива по ссылке - PullRequest
10 голосов
/ 08 сентября 2010

Я могу получить доступ в любом месте внутри многомерного массива через эталонный метод.И я могу изменить его значение.Например:

$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);

Есть ли решение?

Ответы [ 4 ]

6 голосов
/ 08 сентября 2010

Хорошо, я думаю, лучше ответ. Для сброса необходимо получить ссылку на массив контейнеров, а затем сбросить элемент в массиве;

т.е.

$value = & $this->getFromArray('type.conf');

unset  $value['host'];
2 голосов
/ 08 сентября 2010

Ссылки не похожи на жесткие ссылки.Если вы удалите ссылку, это не приведет к сбросу исходного значения.

<?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');
//...
0 голосов
/ 28 сентября 2017

Вот моя функция для отмены вложенных клавиш

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]);
    }
}
0 голосов
/ 14 августа 2014

Создавая некоторые функции для моего фреймворка, думаю, они вас остановят.

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. Функция устанавливает неустановленное значение из массива, используя ссылку

- если окончание ссылки является разделителем, то переменная будет сброшена с именем / ключом перед разделителем
- один момент использования этой функции: вам нужно обновить массив по возвращенному результату функции (в конце примера кода)

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']);

p.s. извините за мой чистый английский

...