PHP:最干净的方式来修改多维数组



我的应用程序中有一个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');

相关内容

  • 没有找到相关文章

最新更新