Люди любят микро-оптимизации. Их легко понимать и легко применять. Но некоторое время назад я прочитал интересную дискуссию о выполнении тернарного оператора в PHP.
Знаете ли вы, какой из следующих фрагментов кода работает быстрее (конечно же, они делают одно и то же)?

// Фрагмент кода 1
$tmp = isset($context['test']) ? $context['test'] : ”;
// Фрагмент кода 2
if (isset($context['test'])) {
$tmp = $context['test'];
} else {
$tmp = ”;
}

Правильный ответ: это зависит от. Большую часть времени они работают примерно с одинаковой скоростью, и вам не нужно ни о чем беспокоиться. Но если $context['test'] содержит большое количество данных, фрагмент 2 работает намного быстрее, чем фрагмент 1.
Далее приведен код, который я использовал для тестирования различных сценариев:

$context = array(’test’ => true);
// заполняем тестовое значение большим количеством данных
for ($i = 0; $i < 100000; $i++) {
$context['test'][$i] = $i;
}
// также можно просто создать большую строку
// $context = str_repeat(’ ‘, 1000000);
// тест производительности
$time = microtime(true);
for ($i = 0; $i < 100; $i++) {
// тестируемый фрагмент кода
$tmp = isset($context['test']) ? $context['test'] : ”;
}
printf("TIME: %0.2d", (microtime(true) - $time) * 1000);

Обратите внимание, что абсолютные показатели производительности не имеют значения. Мы просто хотим сравнить скорость между различными фрагментами кода.
На моем ноутбуке, фрагмент 1 занимает более двух секунд, в то время как фрагмент 2 занимает около 0.05ms. Это большая разница! Но если тестируемая переменная не содержит много данных, скорость почти такая же.
Так почему же тернарный оператор становится настолько медленным при определенных обстоятельствах? И почему это зависит от значения, хранящегося в тестируемой переменной?

Ответ очень прост: тернарный оператор всегда копирует значение, а оператор if – нет. Поскольку PHP использует технику, известную как копирование при записи. Когда значение присваивается переменной, PHP не создает копию содержимого переменной, пока она не будет изменена.

Когда вы пишите оператор $tmp = $context['test'], почти ничего не происходит, переменная $tmp просто становится ссылкой на переменную $context['test'], поэтому он выполняется так быстро. Но как только вы хотите изменить переменную, PHP должен сделать копию исходной переменой.

$tmp = $context['test'];
// здесь происходит копирование
$tmp[] = true;
// копирование также происходит при изменении исходной переменной
// $context['test'][] = true;

Таким образом, скорость тернарного оператора напрямую связана со временем, которое требуется для копирования результата оператора, даже если оно не является абсолютно необходимым, а копирование массива из 100000 элементов занимает много времени.
Если вы используете PHP 5.3, есть более простой способ представить наш оператор с помощью новой конструкции тернарного оператора:
$tmp = $context['test'] ?: ”;

К сожалению, эта новая конструкция имеет такие же недостатки с точки зрения производительности, что и стандартная, даже если PHP может оптимизировать существующую переменную.

(Visited 222 times, 1 visits today)