將扁平的「路徑→值」對應 (如 'a.b.c' => 1) 轉換為巢狀陣列 (['a'=>['b'=>['c'=>1]]]) 是配置解析、表單處理常見需求。本文示範使用 eval 快速實作,並提供不依賴 eval 的迭代參考實作,討論安全性與效能權衡。
$config = array(
'project|page|index' => 'content',
'project|page|nav' => array(
array('image'=>'1.jpg', 'name'=>'home'),
array('image'=>'2.jpg', 'name'=>'about')
),
'project|page|open' => true
);
$result = array();
foreach ($config as $path => $val) {
$keys = explode('|', $path);
$expr = '$result';
foreach ($keys as $k) $expr .= "['$k']";
if (is_array($val)) $expr .= ' = '.var_export($val, true).';';
elseif (is_string($val)) $expr .= ' = \''.$val.'\';';
else $expr .= ' = '.$val.';';
eval($expr);
}
print_r($result);
Array
(
[project] => Array
(
[page] => Array
(
[index] => content
[nav] => Array
(
[0] => Array ( [image] => 1.jpg [name] => home )
[1] => Array ( [image] => 2.jpg [name] => about )
)
[open] => 1
)
)
)
$path 來自使用者輸入,可能構造 ']; system('rm -rf /'); // 導致任意代碼執行。preg_match('/^[a-zA-Z0-9_|]+$/', $path),拒絕含引號、分號、括號等字元。function buildNestedArray($flat, $delimiter='|') {
$nested = array();
foreach ($flat as $path => $value) {
$keys = explode($delimiter, $path);
$ref = &$nested;
foreach ($keys as $key) {
if (!isset($ref[$key]) || !is_array($ref[$key])) $ref[$key] = array();
$ref = &$ref[$key];
}
$ref = $value; // 參考賦值
}
return $nested;
}
$result = buildNestedArray($config);
print_r($result); // 結果相同
$flat = array(
'users|0|name' => 'Alice',
'users|1|name' => 'Bob',
'settings|theme' => 'dark'
);
// buildNestedArray 會正確產生 ['users'=>[['name'=>'Alice'],['name'=>'Bob']], 'settings'=>['theme'=>'dark']]
| 方法 | 時間複雜度 | 記憶體 | 安全性 |
|---|---|---|---|
| eval | O(n * k) + 編譯開銷 | 較高 | 低 (需嚴格過濾) |
| 迭代參考 | O(n * k) | 低 | 高 |
| SPL RecursiveArrayIterator | O(n * k) | 低 | 高 |
eval 適合一次性腳本、受信任資料來源;長期專案請使用迭代參考或封裝為工具類別。完整測試程式碼可至本站下載。