Доступ к многомерному массиву с точечной нотацией

Я хочу написать класс, который сможет обращаться к многомерным массивам с точечной нотацией:

$config->get('bar.baz.foo'); 

Вместо:

 $config['bar']['baz']['foo'] 

Это класс:

 <?php class DotNotation { /** * @var array */ protected $values = array(); public function __construct(array $values) { $this->values = $values; } /** * @param string $path * @param string $default * @return mixed */ public function get($path, $default = null) { $array = $this->values; if (!empty($path)) { $keys = explode('.', $path); foreach ($keys as $key) { if (isset($array[$key])) { $array = $array[$key]; } else { return $default; } } } return $array; } /** * @param string $path * @param mixed $value */ public function set($path, $value) { $link = & $this->values; if (!empty($path)) { $keys = explode('.', $path); foreach ($keys as $key) { if (!isset($link[$key])) { $link[$key] = array(); } if (!is_array($link[$key])) { throw new \RuntimeException("Can not set value for `$key` in `$path` path because it is not array."); } $link = & $link[$key]; } } $link = $value; } /** * @param $path * @param array $values */ public function add($path, array $values) { $get = (array)$this->get($path); $this->set($path, $this->arrayMergeRecursiveDistinct($get, $values)); } /** * @param mixed $parameters */ public function merge($parameters) { $this->add(null, (array)$parameters); } /** * @param string $path * @return bool */ public function have($path) { $keys = explode('.', $path); $array = $this->values; foreach ($keys as $key) { if (isset($array[$key])) { $array = $array[$key]; } else { return false; } } return true; } /** * array_merge_recursive does indeed merge arrays, but it converts values with duplicate * keys to arrays rather than overwriting the value in the first array with the duplicate * value in the second array, as array_merge does. Ie, with array_merge_recursive, * this happens (documented behavior): * * array_merge_recursive(array('key' => 'org value'), array('key' => 'new value')); * => array('key' => array('org value', 'new value')); * * arrayMergeRecursiveDistinct does not change the datatypes of the values in the arrays. * Matching keys' values in the second array overwrite those in the first array, as is the * case with array_merge, ie: * * arrayMergeRecursiveDistinct(array('key' => 'org value'), array('key' => 'new value')); * => array('key' => array('new value')); * * Parameters are passed by reference, though only for performance reasons. They're not * altered by this function. * * If key is integer, it will be merged like array_merge do: * arrayMergeRecursiveDistinct(array(0 => 'org value'), array(0 => 'new value')); * => array(0 => 'org value', 1 => 'new value'); * * @param array $array1 * @param array $array2 * @return array * @author Daniel <daniel (at) danielsmedegaardbuus (dot) dk> * @author Gabriel Sobrinho <gabriel (dot) sobrinho (at) gmail (dot) com> * @author Anton Medvedev <anton (at) elfet (dot) ru> */ protected function arrayMergeRecursiveDistinct(array &$array1, array &$array2) { $merged = $array1; foreach ($array2 as $key => &$value) { if (is_array($value) && isset ($merged[$key]) && is_array($merged[$key])) { if (is_int($key)) { $merged[] = $this->arrayMergeRecursiveDistinct($merged[$key], $value); } else { $merged[$key] = $this->arrayMergeRecursiveDistinct($merged[$key], $value); } } else { if (is_int($key)) { $merged[] = $value; } else { $merged[$key] = $value; } } } return $merged; } } 

Как я могу улучшить этот класс, чтобы не использовать explode ?

Вы можете написать его с помощью strtok() вместо explode() :

 $a = array('foo' => array('bar' => array('baz' => 1))); function resolve(array $a, $path, $default = null) { $current = $a; $p = strtok($path, '.'); while ($p !== false) { if (!isset($current[$p])) { return $default; } $current = $current[$p]; $p = strtok('.'); } return $current; } var_dump(resolve($a, 'foo.bar')); // array('baz' => 1)