我的应用程序中有一个Config
类,它加载静态配置设置并将它们解析为数组。
由于我需要在运行时覆盖一些元素,我需要通过执行此操作来访问Config
- 类中的公共变量; $config->values['onelevel']['twolevel'] = 'changed';
我想创建一个名为override
的方法来为我做这个,但我无法理解这是最好的方法,因为我的配置文件可能会有未知数量的嵌套未来的水平。
做$config->onelevel->twolevel = 'changed'
之类的事情并让__set魔法方法处理嵌套会很可爱,但从我所知道的情况来看,这是不可能的。
最好的方法是什么?
答案 0 :(得分:6)
可以做你想做的事。
这个例子受到Zend_Config的启发,以及ArrayAccess interface上PHP文档中给出的示例。
修改强>
有一个小警告:你需要在表示数组的数据上调用 toArray()
,将其转换为数组,因为类内部需要将数组数据转换为自身的实例,以允许访问对象属性运算符->
:
呃,当然不再需要了,因为它现在实现了ArrayAccess。 ;-)
的 /修改
class Config
implements ArrayAccess
{
protected $_data;
public function __construct( array $data )
{
foreach( $data as $key => $value )
{
$this->$key = $value;
}
}
public function __get( $key )
{
return $this->offsetGet( $key );
}
public function __isset( $key )
{
return $this->offsetExists( $key );
}
public function __set( $key, $value )
{
$this->offsetSet( $key, $value );
}
public function __unset( $key )
{
$this->offsetUnset( $key );
}
public function offsetSet( $offset, $value )
{
$value = is_array( $value ) ? new self( $value ) : $value;
if( is_null( $offset ) )
{
$this->_data[] = $value;
}
else
{
$this->_data[ $offset ] = $value;
}
}
public function offsetExists( $offset )
{
return isset( $this->_data[ $offset ] );
}
public function offsetUnset( $offset )
{
unset( $this->_data[ $offset ] );
}
public function offsetGet( $offset )
{
return isset( $this->_data[ $offset ] ) ? $this->_data[ $offset ] : null;
}
public function toArray()
{
$array = array();
$data = $this->_data;
foreach( $data as $key => $value )
{
if( $value instanceof Config )
{
$array[ $key ] = $value->toArray();
}
else
{
$array[ $key ] = $value;
}
}
return $array;
}
}
编辑2:
通过扩展Config
,甚至可以大大简化ArrayObject
类。另外一个好处是,您也可以将其转换为正确的数组。
class Config
extends ArrayObject
{
protected $_data;
public function __construct( array $data )
{
parent::__construct( array(), self::ARRAY_AS_PROPS );
foreach( $data as $key => $value )
{
$this->$key = $value;
}
}
public function offsetSet( $offset, $value )
{
$value = is_array( $value ) ? new self( $value ) : $value;
return parent::offsetSet( $offset, $value );
}
}
使用示例:
$configData = array(
'some' => array(
'deeply' => array(
'nested' => array(
'array' => array(
'some',
'data',
'here'
)
)
)
)
);
$config = new Config( $configData );
// casting to real array
var_dump( (array) $config->some->deeply->nested->array );
$config->some->deeply->nested->array = array( 'new', 'awsome', 'data', 'here' );
// Config object, but still accessible as array
var_dump( $config->some->deeply->nested->array[ 0 ] );
$config[ 'some' ][ 'deeply' ][ 'nested' ][ 'array' ] = array( 'yet', 'more', 'new', 'awsome', 'data', 'here' );
var_dump( $config[ 'some' ][ 'deeply' ][ 'nested' ][ 'array' ] );
$config[ 'some' ][ 'deeply' ][ 'nested' ][ 'array' ][] = 'append data';
var_dump( $config[ 'some' ][ 'deeply' ][ 'nested' ][ 'array' ] );
var_dump( isset( $config[ 'some' ][ 'deeply' ][ 'nested' ][ 'array' ] ) );
unset( $config[ 'some' ][ 'deeply' ][ 'nested' ][ 'array' ] );
var_dump( isset( $config[ 'some' ][ 'deeply' ][ 'nested' ][ 'array' ] ) );
// etc...
答案 1 :(得分:5)
我也遇到过这个问题,我用这段代码解决了这个问题。但它基于API,如:Config::set('paths.command.default.foo.bar')
。
<?php
$name = 'paths.commands.default';
$namespaces = explode('.', $name);
$current = &$this->data; // $this->data is your config-array
foreach ( $namespaces as $space )
{
$current = &$current[$space];
}
$current = $value;
它只是循环遍历数组并使用引用变量保持当前值的跟踪。
答案 2 :(得分:0)
我使用无限量的参数创建一个函数,并使用func_get_args()
来获取参数,从那里,它只是更新。
答案 3 :(得分:0)
前段时间我需要一个让我通过字符串路径访问数组的函数,也许你可以利用它:
function PMA_array_write($path, &$array, $value)
{
$keys = explode('/', $path);
$last_key = array_pop($keys);
$a =& $array;
foreach ($keys as $key) {
if (! isset($a[$key])) {
$a[$key] = array();
}
$a =& $a[$key];
}
$a[$last_key] = $value;
}
示例:PMA_array_write('onelevel/twolevel', $array, 'value');
答案 4 :(得分:0)
嗯,你说你把它们解析成数组。为什么不将它们解析为stdObjects
,然后根据需要执行$config->onelevel->twolevel = 'changed'
?:)
答案 5 :(得分:0)
您可以自己构建一个类型,即提供您正在寻找的界面,或者您使用您描述的辅助函数。
这是覆盖函数Demo的代码示例:
$array = array(
'a' => array( 'b' => array( 'c' => 'value') ),
'b' => array( 'a' => 'value' ),
);
function override($array, $value) {
$args = func_get_args();
$array = array_shift($args);
$value = array_shift($args);
$set = &$array;
while(count($args))
{
$key = array_shift($args);
$set = &$set[$key];
}
$set = $value;
unset($set);
return $array;
}
var_dump(override($array, 'new', 'a', 'b', 'c'));