PHPで動的n次元配列追加をしたいです。 例えば複数の階層を持つ配列です。


流行りライド
[PHPで動的n次元配列追加をしたいです。 例え… - Qiita](http://qiita.com/ProjectICKX/items/07df12785fca9b8840d7)をもうちょっと真面目に対応したもの

# 仕様

- 最下層以外は全てキーとみなす
- "("の前に任意の文字が無い場合は、配列の追加とみなす

# 実装

```php

echo str_repeat('=', 36), PHP_EOL;
echo "お題：a((b((c))d((e)))) => ['a' => [['b'=>[['c']], 'd' => [['e']]]]]", PHP_EOL;
echo str_repeat('=', 36), PHP_EOL;
echo "['a' => [['b'=>[['c']], 'd' => [['e']]]]]を実際展開するとこうなる。", PHP_EOL;
var_dump(['a' => [['b'=>[['c']], 'd' => [['e']]]]]);
echo PHP_EOL;

$target = 'a((b((c))d((e))))';

//比較的真面目parser
$stacker = parser($target);

//一括DONE
$result = [];
foreach ($stacker as $stack) {
	$value = array_pop($stack);
	$result = set_lowest($result, $stack, $value);
}

echo PHP_EOL;
echo "ウチの実行結果。", PHP_EOL;
var_dump($result);
echo PHP_EOL;

echo str_repeat('=', 36), PHP_EOL;
echo "拡張お題：a((((c))((e)))) => ['a' => [[[['c']], [['e']]]]]", PHP_EOL;
echo str_repeat('=', 36), PHP_EOL;
echo "['a' => [[[['c']], [['e']]]]]を実際展開するとこうなる。", PHP_EOL;
var_dump(['a' => [[[['c']], [['e']]]]]);
echo PHP_EOL;

$target = 'a((((c))((e))))';

//比較的真面目parser
$stacker = parser($target);

//一括DONE
$result = [];
foreach ($stacker as $stack) {
	$value = array_pop($stack);
	$result = set_lowest($result, $stack, $value);
}

echo PHP_EOL;
echo "ウチの実行結果。", PHP_EOL;
var_dump($result);
echo PHP_EOL;

/**
 * 指定された文字列を解析し、チャンクとして返します。
 *
 * @param	string	$target	解析対象の文字列
 * @return	array	解析済みのチャンク 階層ツリーごとに1配列を持つ配列
 */
function parser ($target) {
	$key_buffer = [];
	$value_buffer = [];
	$stacker = [];

	for ($i = 0, $max = mb_strlen($target, ENCODING);$i < $max;$i++) {
		$char = mb_substr($target, $i, 1, ENCODING);
		switch ($char) {
			case '(' :
				$key_buffer[] = empty($value_buffer) ? count(get_lowest($stacker, array_keys($key_buffer))) : implode('', $value_buffer);
				$value_buffer = [];
				break;
			case ')':
				if (!empty($value_buffer)) {
					$key_buffer[] = 0;
					$key_buffer[] = implode('', $value_buffer);
					$stacker[] = $key_buffer;
				}
				array_pop($key_buffer);
				array_pop($key_buffer);
				$value_buffer = [];
				break;
			default:
				$value_buffer[] = $char;
				break;
		}
	}

	return $stacker;
}

/**
 * 指定された階層にある値を設定します。
 *
 * @param	array	$array	配列
 * @param	mixed	$keys	階層
 * @return	array	設定後の配列
 */
function set_lowest ($array, $keys, $value) {
	$keys = (array) $keys;
	if (empty($array)) {
		$tmp =& $array;
	} else {
		$tmp =& $array[array_shift($keys)];
	}

	foreach ($keys as $key) {
		if (!isset($tmp[$key])) {
			$tmp[$key] = null;
		}
		$tmp =& $tmp[$key];
	}
	$tmp = $value;
	return $array;
}

/**
 * 指定された階層にある値を取得します。
 *
 * @param   array   $array  配列
 * @param   mixed   $keys   階層
 * @return  mixed   指定された改造にある値
 */
function get_lowest ($array, $keys) {
	foreach ((array) $keys as $key) {
		if (isset($array[$key])) {
			$array = $array[$key];
		} else {
			return null;
		}
	}
	return $array;
}
```

# 実行結果

```
====================================
お題：a((b((c))d((e)))) => ['a' => [['b'=>[['c']], 'd' => [['e']]]]]
====================================
['a' => [['b'=>[['c']], 'd' => [['e']]]]]を実際展開するとこうなる。
array(1) {
  ["a"]=>
  array(1) {
    [0]=>
    array(2) {
      ["b"]=>
      array(1) {
        [0]=>
        array(1) {
          [0]=>
          string(1) "c"
        }
      }
      ["d"]=>
      array(1) {
        [0]=>
        array(1) {
          [0]=>
          string(1) "e"
        }
      }
    }
  }
}


ウチの実行結果。
array(1) {
  ["a"]=>
  array(1) {
    [0]=>
    array(2) {
      ["b"]=>
      array(1) {
        [0]=>
        array(1) {
          [0]=>
          string(1) "c"
        }
      }
      ["d"]=>
      array(1) {
        [0]=>
        array(1) {
          [0]=>
          string(1) "e"
        }
      }
    }
  }
}

====================================
拡張お題：a((((c))((e)))) => ['a' => [[[['c']], [['e']]]]]
====================================
['a' => [[[['c']], [['e']]]]]を実際展開するとこうなる。
array(1) {
  ["a"]=>
  array(1) {
    [0]=>
    array(2) {
      [0]=>
      array(1) {
        [0]=>
        array(1) {
          [0]=>
          string(1) "c"
        }
      }
      [1]=>
      array(1) {
        [0]=>
        array(1) {
          [0]=>
          string(1) "e"
        }
      }
    }
  }
}


ウチの実行結果。
array(1) {
  ["a"]=>
  array(1) {
    [0]=>
    array(2) {
      [0]=>
      array(1) {
        [0]=>
        array(1) {
          [0]=>
          string(1) "c"
        }
      }
      [1]=>
      array(1) {
        [0]=>
        array(1) {
          [0]=>
          string(1) "e"
        }
      }
    }
  }
}
```