PHP:修改多维数组最干净的方法?

Ind*_*ial 6 php arrays oop multidimensional-array

我的Config应用程序中有一个类,它加载静态配置设置并将它们解析为数组.
由于我需要在运行时覆盖一些元素,我需要Config通过执行此操作来访问-class中的公共变量;$config->values['onelevel']['twolevel'] = 'changed';

我想创建一个override为我做这个调用的方法,但是我无法理解这是最好的方法,因为我的配置文件将来可能会有未知数量的嵌套级别.

做一些类似的事情$config->onelevel->twolevel = 'changed'并让__set魔法方法来处理嵌套会很可爱,但从我所知道的情况来看,这是不可能的.

最好的方法是什么?

Dec*_*ler 6

你可以做你想做的事.

这个例子受到Zend_ConfigArrayAccess接口上PHP文档中给出的示例的启发.

编辑:
有一个小警告:你需要调用toArray()表示数组的数据,将其转换为数组,因为类内部需要将数组数据转换为自身的实例,以允许使用object属性操作符进行访问->:

呃,当然不再需要了,因为它现在实现了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;
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑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 );
    }
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

$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...
Run Code Online (Sandbox Code Playgroud)


Eri*_*off 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;
Run Code Online (Sandbox Code Playgroud)

它只是循环遍历数组并使用引用变量保持当前值的跟踪.