unset a element of an array via reference
I can access anywhere inside the multi-dimensional an array via reference method. And I can change the its value. For example:
$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',
开发者_Python百科 'pass' => '12345',
'host' => '-- changed ---'
'port' => '3306'
)
);
BUT, I can't destroy the that section:
// normally success
unset($conf['type']['conf']['host']);
// fail via reference
$value = & $this->getFromArray('type.conf.host');
unset($value);
Is there a solution?
Ok, better answer I think. In order to unset , you should get a reference to the container array, then unset the element within the array;
i.e.
$value = & $this->getFromArray('type.conf');
unset $value['host'];
References are not like hard-links. If you unset a reference, this will not unset the origin value.
<?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
Why not write a little Config
class which abstracts the data (array)? Since objects are always passed by reference you won't need to handle this at your own.
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');
//...
Here is my function for unsetting nested keys
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]);
}
}
Creating some functions for my framework, think they halp you.
1. Function set value in array using reference for navigation
- if reference ending by name/key, this name/key will be equal setting value
- if reference ending by delimiter, last name/key will be array with setting value
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 set unset value from array using reference
- if reference ending is delimiter, then will be unset varible with name/key befor delimiter
- one moment of using this function: you need update array by returned result of function (in the end of code example)
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. sorry for my pure English
精彩评论