2011-02-25 71 views
0

問題PHP數組:修改值當陣列的結構是未知

如何在PHP數組修改的值,如果你不事先知道數組的結構?

在下文陣列,我在陣列,其中「系統」 ==「的knoppix」的一部分以改變「fave_color」到「藍色」 ...問題是我不知道數組的結構將在運行什麼,所以我不能簡單地做

$myarray['settings']['user_prefs']['otherhost']['fave_color'] = 'blue'; 

這是行不通的,因爲嵌套在運行時的fave_color未知

此外,我感興趣的fave_color密鑰是,具體取決於系統陣列密鑰

我必須找到值爲'knoppix'的人,然後更改相應的'fave_color'值,確保不會更改數組中的任何其他fave_color值。

'settings' => array(
    'user_prefs'=>array(
    'localhost'=>array(
     'fave_color'=>'orange', 
     'system' =>'unbuntu', 
    ), 
    'otherhost'=>array(
     'fave_color'=>'yellow', 
     'system' =>'knoppix', 
    ),   
), 
), 
+0

你是什麼意思你不知道數組的結構?它是隨機的嗎?必須有一些結構,或者你不知道你想要改變什麼樣的價值。 – meagar 2011-02-25 21:52:37

+0

我知道有一個關鍵的'系統',我知道有一個相應的兄弟關鍵'fave_color'...我不知道這些關鍵將位於數組中的位置......(我不知道是否它會在設置或設置/ user_prefs或設置/ otherhost),當它需要將fave_color從'黃色'更改爲'藍色'。此外,我不能只改變fave_color,但我必須更改*特定* fave_color在system =='knoppix'的分支中。 – dreftymac 2011-02-25 21:56:49

+0

cakephp :: set是另一個選項,請參閱「flatten」方法。 – dreftymac 2011-10-31 14:22:23

回答

2

您可以使用array_walk_recursive並檢查密鑰是否等於'knoppix'。

function findKnoppix(&$value, $key) 
{ 
    if($value == 'knoppix') $value = 'NEW VALUE'; 
} 

array_walk_recursive($myArray, 'findKnoppix'); 
+0

是的,但後來我怎麼修改對應的fave_color鍵下的值 – dreftymac 2011-02-25 22:03:27

+0

值是通過引用傳遞的,我已經更新了我的例子。 – Nazariy 2011-02-25 22:10:35

1

我知道這個問題是一對夫婦個月大,但我遇到了同樣的問題,有解決辦法,我真的很喜歡過來了,想通有人因此不得不之前問一下吧。首先,有幾個想法:

1)即使您必須來回轉換,您是否可以使用XPath或本地PHP數組以外的其他任何東西?當然,請衡量性能點擊量,但請嘗試一下 - 使用your related question中描述的查詢方式可能會爲您節省頭痛,而不會產生巨大的開銷。

2)你可以改變數組的結構嗎?如果system是一個重要的關鍵,它是否有一個很好的理由嵌套在這個深度?如果您將數組重新組織爲「按系統類型設置」,則該數組可能不夠緊湊,但它可能更容易遍歷。

最後,這是我對我遇到的問題的解決方案,我認爲您可以適應您的問題。如果您需要添加更復雜的邏輯,比如檢查必需的兄弟,我會爲回調函數添加一個可選的第三個參數。

/** 
* Sets key/value pairs at any depth on an array. 
* @param $attrs an array of key/value pairs to be set/added 
* @param $data the array you want to affect 
*/ 
function setAttributes($attrs, &$data) 
{ 
    foreach ($attrs as $name => $value) { 
     if (strpos($name, '.') === false) { 
      // If the array doesn't contain a special separator character, 
      // just set the key/value pair. If $value is an array, 
      // you will set nested key/value pairs just fine. 
      $data[$name] = $value; 
     } else { 
      // In this case we're trying to target a specific nested key 
      // without overwriting any other siblings/ancestors. The period 
      // is my separator character -- you can change it to any unique 
      // string that is invalid for a key in your system. 
      $keys = explode('.', $name); 
      // Set the root of the tree. 
      $opt_tree =& $data; 
      // Start traversing the tree using the specified keys. 
      while ($key = array_shift($keys)) { 
       // If there are more keys after the current one... 
       if ($keys) { 
        if (!isset($opt_tree[$key]) || !is_array($opt_tree[$key])) { 
         // Create this node if it doesn't already exist. 
         $opt_tree[$key] = array(); 
        } 
        // Here's the fun bit -- redefine the "root" of the tree 
        // (assignment by reference) then process the next key. 
        $opt_tree =& $opt_tree[$key]; 
       } else { 
        // This is the last key to check, so assign the value. 
        $opt_tree[$key] = $value; 
       } 
      } 
     } 
    } 
} 

使用範例:

$x = array(); 
setAttributes(array('foo' => 'bar', 'baz' => array('quux', 42)), $x); 
print_r($x); // $x has the same structure as the first argument 
setAttributes(array('jif.snee' => 'hello world'), $x); 
print_r($x); // $x now has a jif key whose value is snee => hello world 
    // if jif.snee already existed, this call would have overwritten 
    // that value without modifying any other values