我有一堆字符串,如" memory.caching"和" server.base.url"。在我的配置对象中键的每一部分"。"等于一个数组中的一个键,该值可能是另一个数组,最后一个是值,所以" memory.caching"等于。
$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;
}
关于如何实现这一目标的任何想法?
答案 0 :(得分:2)
设置值...
public function set($path, $value, $delimiter = '.') {
$tokens = explode($delimiter, $path);
$currentPiece = &$this->config;
foreach($tokens as $token) {
$currentPiece = &$currentPiece[$token];
}
$currentPiece = $value;
}
获得价值......
public function get($path, $delimiter = '.') {
$tokens = explode($delimiter, $path);
$currentPiece = $this->config;
while ($token = array_shift($tokens)) {
$currentPiece = $currentPiece[$token];
}
return $currentPiece;
}
答案 1 :(得分:0)
有点可怕,但绝对有效的方法是使用eval()
(邪恶):
public function set($k, $v) {
eval('$this->config["'.implode('"]["', explode(".", $k)).'"] = $v;');
}
答案 2 :(得分:0)
虽然此问题已经得到解答(并接受),但我会将此版本发布给未来的访问者:
(可能会遗漏一些支票,我有几个版本的这个)
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非常有用,但没有一种神奇的方法可以用语义对它进行别名。