2011-08-26 57 views
6

我的應用程序中有一個Config類,它加載了靜態配置設置並將它們解析爲數組。
因爲我需要在運行時重寫一些元素,所以我需要訪問Config-類中的公共變量; $config->values['onelevel']['twolevel'] = 'changed';PHP:最簡單的方法來修改多維數組?

我想做一個叫做override的方法,這對我來說是這樣的,但是我無法得到我的頭腦,因爲我的配置文件可能會獲得未知數量的嵌套級別未來。

$config->onelevel->twolevel = 'changed'這樣的事情會很可愛,讓__set魔術方法來處理嵌套,但從我所知道的情況來看,這是不可能的。

這樣做的最好方法是什麼?

+0

也許這樣的數據不能用詞語「配置」來表示;將其存儲在數據庫中 – Dor

+0

當我的答案更符合您的問題要求時,爲什麼選擇ErikPerik的答案作爲最佳答案?並不是說我不想授予ErikPerik的代表點。我只是好奇你爲什麼覺得他的答案是更好的答案? –

+0

我原本以爲他的解決方案很乾淨,直到我看到你的更新版本。利用'ArrayObject'是我以前從未做過的事情,絕對需要查看它! – Industrial

回答

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... 
+0

嗨fireeyedboy。請看看這裏,看看你是否有任何想法; http://stackoverflow.com/questions/7254675/extending-arrayobject-in-php-properly – Industrial

+0

@Industrial:巧合的是,我只是看着這個問題。 :) –

0

我做了一個無限期參數的函數,並使用func_get_args()來獲取參數,從那裏,它只是更新。

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');

+0

哎呀,謝謝。固定 – Crack

0

好了,你說你解析他們進入陣列。爲什麼不把它們解析爲stdObjects,然後只需要$config->onelevel->twolevel = 'changed'?:)

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; 

它只是在數組中循環並用參考變量保持跟蹤當前值。

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'));