Удобный доступ к конфигу/массиву

Долго думал как назвать пост. Иногда очень достают километровые строки для доступа к массиву(как правило километры - именно в конфиге), например:

$this->config->config['siteconfig']['someavatar']['normal']['height']

А хочется что - то более лаконичное, вроде

$this->_siteConfig('someavatar', 'normal', 'height');

или может даже

$this->_siteConfig('someavatar/normal/height')

Красота, не правда ли? :) Конечно, может я и сам виноват что сделал такое ветвистое дерево конфига, и теперь что бы получить обычный размер аватарки приходиться строить "паравозик" из "вагончиков" в названии которых можно легко опечататься, тем более это несколько усложняет чтение кода.

Думаю, понятно, что такой массив может быть не только конфигом - далеко ходить не надо - хоть тот же json %)

Такая задача "удобного" доступа легко решается в 2 строчки используя eval() и implode(). Условимся, что использовать eval() не будем, в том числе и потому, что это откровенная дыра, плохая манера и в будующем эту функцию уберут.

Можно воспользоваться двумя ключевыми моментами: функция с переменным количеством аргументов и использование ссылок, перебирая "вагончики" друг за другом вдоль всего "поезда".

Вариант для CodeIgniter

В контексте метода, расширяющего контроллер это выглядит так:

abstract class MY_Controller extends Controller {
. . . .
/**
* Получение элементов конфига сайта.
* Количество аргументов метода - любое.
* Если задан всего один аргумент - строка, и в ней есть '/'
* то этот путь будет разобран как элементы конфига
* Примеры использования(одинаковый результат):
* _siteConfig('box', 'weight')
* _siteConfig('box/weight')
* @return mixed значение
*/
public function & _siteConfig() {
$args = func_get_args();
$args_count = count($args);
$config_separator = '/';
if ($args_count == 1 && strpos($args[0], $config_separator)) {
$args = explode($config_separator, $args[0]);
$args_count = count($args);
}

$sc = &$this->config->config['siteconfig'];
for($i = 0; $i < $args_count; $i++) {
$sc = & $sc[$args[$i]];
}
return $sc;
}
}

Можно изменить:

  • $config_separator - разделитель ключей массивов("пути"). Можно заменить на любой символ/последовательность символов. Как душе угодно.
  • $sc - ссылка на массив с которым нужно работать(корень массива/дерева конфиругации). У меня это $this->config->config['siteconfig'] - одна из секций конфига CodeIgniter приспособленная чисто под собственные настройки сайта

Как уже написанно в коде, результат вызова методов(в контексте контроллера - наследника MY_Controller)

$v1 = $this->_siteConfig('box', 'weight');
$v2 = $this->_siteConfig('box/weight');

будет одинаков.

Вариант standalone - без CodeIgniter

А теперь приминительно к ситуации что нет у нас codeIgniter :) и такое тоже бывает ;)

Пусть есть некий конфиг(ну или просто массив, не важно):


$a['siteconfig'] = array(
'box' => array(
'weight' => 100,
"color" => "red"),
'phone' => 100500,
'debug' => true );

Немного переделав метод(всего лишь изменив $sc) для контроллера можно получить функцию, которая будет работать с этим массивом:

function & _siteConfig() {
$args = func_get_args();
$args_count = count($args);
$config_separator = '/';
if ($args_count == 1 && strpos($args[0], $config_separator)) {
$args = explode($config_separator, $args[0]);
$args_count = count($args);
}

$sc = &$GLOBALS['a']['siteconfig'];
for($i = 0; $i < $args_count; $i++) {
$sc = & $sc[$args[$i]];
}
return $sc;
}

echo "phone: " . _siteConfig('phone') . " \n"; // выведет 100500
echo "box, color: " . _siteConfig('box', 'color') . " \n"; // выведет red
echo "box/color: " . _siteConfig('box/color') . " \n"; // также выведет red

А что касается производительности, не надо
сходить с ума - это не частая операция, и
есть куча мест где действительно надо оптимизировать.