PHP通过对变量的引用从数组中赋值.改变变量会改变数组中的值


PHP assign value from array by reference to variable. Change variable would change value in array

我有一堆字符串,如"内存"。缓存"answers"server.base.url"。在我的配置对象中,键"。"的每个部分都等于数组中的一个键,值可以是另一个数组,最后一个值是"内存"。缓存"等同于。

$config = array(
  "memory" => array(
    "caching" => true
  )
);

我想创建一个setter方法。我最终得到了下面的代码,但这并不适用于三到四个层次的深度。如果不添加多个else/if子句,我怎么能做到呢?

public function set($k, $v) {
  $parts = explode(".", $k);
  // Start sucky code.
  if (count($parts) == 2)
  {
    $this->config[$parts[0]][$parts[1]] = $val;
  }
}

我在考虑某种形式的循环,通过引用赋值,像下面这样,但我不能让它工作。

public function set($k, $v) {
  $parts = explode(".", $k);
  $tmp = $this->config;
  foreach ($parts as $p) {
    $tmp &= $tmp[$p];
  }
  $tmp = $v;
}

有什么好主意吗?

设置一个值…

public function set($path, $value, $delimiter = '.') {
    $tokens = explode($delimiter, $path);
    $currentPiece = &$this->config;
    foreach($tokens as $token) {
       $currentPiece = &$currentPiece[$token];
    }
    $currentPiece = $value;  
}

CodePad .

获取一个值…

public function get($path, $delimiter = '.') {
    $tokens = explode($delimiter, $path);
    $currentPiece = $this->config;
    while ($token = array_shift($tokens)) {
        $currentPiece = $currentPiece[$token];
    }
    return $currentPiece;
}

CodePad .

使用eval() (evil):

public function set($k, $v) {
  eval('$this->config["'.implode('"]["', explode(".", $k)).'"] = $v;');
}

虽然这个问题已经得到了回答(和接受),但我将把这个版本放在那里供将来的访问者使用:

(可能缺少一些检查,我有几个版本正在使用)

class Map
{
    protected $_array = array();
    protected $_separator;
    public static function get(Array $array, $key, $separator)
    {
        $parts = explode($separator, $key);
        $key = array_shift($parts);
        while (!empty($parts))
        {
            if (!isset($array[$key]) || !is_array($array[$key]))
            {
                return null;
            }
            $array = &$array[$key];
            $key = array_shift($parts);
        }
        return isset($array[$key]) ? $array[$key] : null;
    }
    public static function has(Array $array, $key, $separator)
    {
        $parts = explode($separator, $key);
        $key = array_shift($parts);
        while (!empty($parts))
        {
            if (!isset($array[$key]) || !is_array($array[$key]))
            {
                return false;
            }
            $array = &$array[$key];
            $key = array_shift($parts);
        }
        return isset($array[$key]);
    }
    public static function set(&$array, $key, $value, $separator)
    {
        $parts = explode($separator, $key);
        $key = array_shift($parts);
        while (!empty($parts))
        {
            if (!isset($array[$key]) || !is_array($array[$key]))
            {
                $array[$key] = array();
            }
            $array = &$array[$key];
            $key = array_shift($parts);
        }
        $array[$key] = $value;
    }
    public static function bind(&$array, $key, &$variable, $separator)
    {
        $parts = explode($separator, $key);
        $key = array_shift($parts);
        while (!empty($parts))
        {
            if (!isset($array[$key]) || !is_array($array[$key]))
            {
                $array[$key] = array();
            }
            $array = &$array[$key];
            $key = array_shift($parts);
        }
        if (isset($array[$key]))
        {
            $variable = $array[$key];
        }
        $array[$key] = &$variable;
    }
    public static function remove(&$array, $key, $separator)
    {
        $parts = explode($separator, $key);
        $key = array_shift($parts);
        while (!empty($parts))
        {
            if (!isset($array[$key]) || !is_array($array[$key]))
            {
                return;
            }
            $array = &$array[$key];
            $key = array_shift($parts);
        }
        unset($array[$key]);
    }
    public function __construct(&$array, $separator)
    {
        if (!is_array($array))
        {
            $array = array();
        }
        $this->_array = $array;
        $this->_separator = (string) $separator;
    }
    public function __get($key)
    {
        return static::get($this->_array, $key, $this->_separator);
    }
    public function __isset($key)
    {
        return static::has($this->_array, $key, $this->_separator);
    }
    public function __set($key, $value)
    {
        static::set($this->_array, $key, $value, $this->_separator);
    }
    public function __unset($key)
    {
        static::remove($this->_array, $key, $this->_separator);
    }
    public function get_array()
    {
        return $this->_array;
    }
}

并像这样使用:

$array = array(
    'foo' => array(
        'bar' => array(
            'hello' => 'world',
        ),
    ),
);
$map = new Map($array, '.');
var_dump($map->{'foo.bar.hello'}); 
//string(5) "world"
$map->{'foo.bar.goodbye'} = 'universe';
unset($map->{'foo.bar.hello'});
var_dump($map->get_array());
// array(1) {
//   ["foo"]=>
//   array(1) {
//     ["bar"]=>
//     array(1) {
//       ["goodbye"]=>
//       string(8) "universe"
//     }
//   }
// }
var_dump(isset($map->{'foo.bar.goodbye'}));
// true

Bind非常有用,但是没有一个神奇的方法可以在语义上别名它。