Хватит использовать устаревшие методы оптимизации в PHP
Преждевременная оптимизация — корень всех зол
Мы все слышали эту цитату. Возможно, десятки раз. Но многие разработчики продолжают использовать старые добрые методы оптимизации.
Мне кажется, что любовь к "трюкам производительности" часто возникает у разработчиков с 10+ летним стажем. Они знают множество трюков, и у них есть мысли вроде "хуже не будет" и "производительность никогда не бывает лишней". Другой случай — это разработчики, которые хотят показать своё мастерство. "Ха-ха — посмотрите, какой трюк я знаю".
В результате мы получаем вот такой странный код:
<?php
$users = getUsers();
$usrsAmt = sizeof($users);
for ($i = 0; $i < $usrsAmt; $i++>) {
if (isset($users[$i]['name'][17])) {
$users[$i]['name'] = substr($users[$i]['name']) . '...(truncated)';
echo 'user ', $i, ' name was truncated';
}
}
Почему sizeof
вместо count
? Почему не foreach
? Что за чертовщина с echo
? isset
индекса строки???
Всё это — ради "производительности". По крайней мере, мы так думали десять лет назад. А на самом деле и десять лет назад не было смысла использовать такие трюки. Да, некоторые странные вещи могли дать небольшой выигрыш в производительности, но…:
- Если действительно важны наносекунды — вы используете не тот инструмент (PHP)
- С вероятностью 99,99% узким местом вашего кода является не синтаксис цикла или двойные кавычки вместо одинарных
Всё ещё не убедились? А что, если я скажу, что некоторые старомодные советы больше не имеют смысла?
Я выбрал 5 самых распространённых приёмов, известных каждому разработчику, работающему с PHP 5.6 и старше. Все они не имеют смысла в PHP 8.x+
1. Использование isset() вместо strlen()
Это отличный пример идиоматического кода. Вместо того чтобы проверять фактическую длину строки, нам предложили просто проверить наличие N-го символа в строке.
<?php
$string = "some kind of string";
// нам предлагают заменить это
$stringIsLongerThan5 = strlen($string) > 5;
// на это
$stringIsLongerThen5 = isset($string[6]);
И в PHP 5.6 действительно есть разница в производительности. Мои локальные тесты показали прирост около 40%.
Но… это потеряло смысл после выхода PHP 7.0. Обработка строк была значительно улучшена, и теперь скорость осталась прежней.
Мне не удалось измерить разницу даже на наборе из 500K строк.
2. Использование цикла for вместо foreach
Всё просто — мы знаем, что цикл for быстрее цикла foreach.
<?php
$array = getHugeArray();
// нам предлагают заменить это
foreach ($array as &$item) {
$item = process($item);
}
// на это
$size = count($array);
for ($i = 0; $i < $size; $i++) {
$array[$i] = process($array[$i]);
}
Ладно, технически это всё ещё имеет смысл. Да, цикл for всё равно быстрее.
Но:
- Цикл foreach был значительно улучшен, и накладные расходы стали намного меньше, чем годы назад.
- Нет смысла использовать этот трюк, пока в вашем массиве не будет сотни тысяч элементов.
Так что да, эта штука работает, но не стоит использовать этот трюк до тех пор, пока не понадобится просмотреть огромный объём данных. В противном случае вы просто сделаете свой код менее читабельным без веской причины.
3. Использование одинарных кавычек вместо двойных
Логика была простой — PHP обрабатывает строки с одинарными кавычками как простые строки, а строки с двойными кавычками — как шаблонные строки, которые могут содержать переменные. И идея была проста — используйте строки с двойными кавычками только в том случае, если вы хотите передать в них переменную.
<?php
// нам предлагают заменить это
$userName = "John";
$userAge = "29";
$userNickname = "Super{$userName}{$userAge}";
// на это
$userName = 'John';
$userAge = '29';
$userNickname = "Super{$userName}{$userAge}";
Честно говоря, даже в те времена я сомневался в этом трюке. Серьёзно, я понятия не имею, что, черт возьми, нужно закодировать, чтобы получить реальный эффект от этой штуки.
Но теперь это официально не имеет смысла. Обработка строк была значительно улучшена в релизе PHP 7.0, и теперь они невероятно быстры. Не стесняйтесь использовать двойные кавычки везде. Серьёзно, перестаньте заморачиваться с этими кавычками.
4. Использование конкатенации вместо шаблонов строк
Идея была очень похожа на предыдущую. Шаблоны строк работали медленнее, чем простые, поэтому разработчики решили, что быстрее будет использовать конкатенацию строк, а не шаблоны (почему?). Даже если это выглядит уродливее, чем шаблоны строки.
<?php
// нам предлагают заменить это
$userName = "John";
$userAge = "29";
$userNickname = "Super{$userName}{$userAge}";
// на это
$userName = 'John';
$userAge = '29';
$userNickname = 'Super' . $userName . $userAge;
Суть та же — делать это после PHP 7+ не имеет смысла. Скажу больше — автор движка PHP утверждает, что в современном PHP конкатенация может быть даже медленнее, чем шаблоны строк.
5. Использование префиксного инкремента вместо постфиксного
<?php
// нам предлагают заменить это
$i++;
// на это
$++i;
По-моему, это выглядит глупо. Серьёзно, не может быть, чтобы эта штука дала какое-то значительное улучшение производительности. Но я слишком часто видел это в реальном коде, чтобы сомневаться, что люди верят в это.
Да, 10 лет назад разница в скорости была крошечной, но Zend Engine постоянно совершенствовался, и теперь разница меньше, чем погрешность измерений, даже когда выполняются миллионы операций (хотел бы я посмотреть на PHP-код, которому действительно нужно делать инкрементацию миллионы раз).
Подводя итог, можно сказать, что хватит использовать трюки микрооптимизации в PHP, жертвуя читабельностью кода ради мнимого повышения производительности. Более того, перестаньте учить этим трюкам новичков. Это бессмысленно.
Часть этих трюков просто не работает, а часть даст минус 0,001 микросекунды во времени выполнения скрипта. Это бессмысленно. Один SQL-запрос, не попавший в индекс, уничтожит все эти "улучшения". И наоборот, правильно используемый кэш может дать секунды разницы вместо микросекунд.
Вы знаете другие бессмысленные "оптимизации", которые только портят читабельность кода? Поделитесь в комментариях.