Ну, вопрос был достаточно интересным, так что я не мог удержаться, чтобы немного повозиться. : -)
Итак, вот мои выводы. Ваша реализация , вероятно, самая простая и понятная . И это работает, так что я бы не стал беспокоиться о поиске другого решения. На самом деле, сколько звонков ты получишь в конце? Стоит ли разница в производительности (я имею в виду " super ultra невероятно быстро " и " почти вдвое быстрее ")?
Если оставить в стороне, , если производительность действительно является проблемой (получение тысяч вызовов), то есть способ сократить время выполнения, если вы повторно просматриваете массив.
В вашей версии наибольшее бремя приходится на строковые операции в вашей функции get
. Все, что касается манипуляции со строками , обречено на провал в этом контексте. И это действительно было так со всеми моими первыми попытками решить эту проблему.
Трудно не трогать строки , если нам нужен такой синтаксис, но мы можем по крайней мере ограничить количество операций со строками, которые мы делаем .
Если вы создаете хеш-карту (хеш-таблицу), чтобы вы могли сгладить ваш многомерный массив до глубокой структуры на один уровень, то большинство вычислений выполняются за один раз расходы. Это окупается, потому что таким образом вы можете почти напрямую искать свои значения с помощью строки , предоставленной в вашем вызове get
.
Я придумал что-то вроде этого:
<?php
class Demo {
protected $_values = array();
protected $_valuesByHash = array();
function createHashMap(&$array, $path = null) {
foreach ($array as $key => &$value) {
if (is_array($value)) {
$this->createHashMap($value, $path.$key.'.');
} else {
$this->_valuesByHash[$path.$key] =& $value;
}
}
}
function __construct(array $values) {
$this->_values = $values;
$this->createHashMap($this->_values);
// Check that references indeed work
// $this->_values['general'][0]['special']['number'] = 28;
// print_r($this->_values);
// print_r($this->_valuesByHash);
// $this->_valuesByHash['general.0.special.number'] = 29;
// print_r($this->_values);
// print_r($this->_valuesByHash);
}
public function get($hash, $default = null) {
return isset($this->_valuesByHash[$hash]) ? $this->_valuesByHash[$hash] : $default;
}
}
$test = new Demo(array(
'simple' => 27,
'general' => array(
'0' => array(
'something' => 'Hello World!',
'message' => 'Another message',
'special' => array(
'number' => 27
)
),
'1' => array(
'something' => 'Hello World! #2',
'message' => 'Another message #2'
),
)
));
$start = microtime(true);
for ($i = 0; $i < 10000; ++$i) {
$simple = $test->get('simple', 'default');
$general_0_something = $test->get('general.0.something', 'default');
$general_0_special_number = $test->get('general.0.special.number', 'default');
}
$stop = microtime(true);
echo $stop-$start;
?>
Сеттер еще не реализован, и вам придется изменить его для альтернативного синтаксиса (разделитель #
), но я думаю, что он передает идею.
По крайней мере, на моем тестовом стенде для выполнения этого требуется половину времени по сравнению с исходной реализацией. Тем не менее, доступ к необработанным массивам быстрее , но разница в моем случае составляет около 30-40%. На данный момент это было лучшее, чего я мог достичь. Я надеюсь, что ваше реальное дело недостаточно велико, чтобы я столкнулся с некоторыми ограничениями памяти на этом пути. : -)