我的应用程序中有一个Config
类,它加载静态配置设置并将其解析为数组。
由于我需要在运行时重写一些元素,我需要通过这样做来访问Config
类内部的公共变量;$config->values['onelevel']['twolevel'] = 'changed';
我想做一个叫做override
的方法,为我做这件事,但我不能得到我的头周围什么是最好的方法来做到这一点,因为我的配置文件可能会在未来得到未知数量的嵌套水平。
这将是可爱的做一些像$config->onelevel->twolevel = 'changed'
,让__set魔术方法来照顾嵌套,但从我可以告诉,这是不可能的。
最好的方法是什么?
你想做什么就做什么。
这个例子很大程度上是受Zend_Config和PHP文档中关于ArrayAccess接口的例子的启发。
编辑:
有一个小小的警告:你需要调用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...
我也遇到过这个问题,我用这段代码解决了这个问题。然而,它是基于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;
它只是通过一个引用变量循环遍历数组并保存当前值的轨迹
我会用不确定数量的参数做一个函数,并使用func_get_args()
来获取参数,从那里,它只是更新。
你说你要把它们解析成数组。为什么不将它们解析为stdObjects
,然后按您的需要简单地执行$config->onelevel->twolevel = 'changed'
呢?:)
您可以自己构建一个类型,它提供您正在寻找的接口,或者您使用您描述的辅助函数。
这是一个重写函数的代码示例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'));
前段时间我需要一个函数,可以让我通过字符串路径访问数组,也许你可以使用它:
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');