Статьи

Ленивый PHP: часть 1

Многое можно сказать о лени, особенно когда речь идет о PHP. Я не говорю о растяжке на диване, а о методах, которые вы можете использовать, чтобы сделать ваш PHP-код быстрее.

Как работает PHP (на расстоянии)
Когда PHP-скрипт запрашивается с вашего сервера, перед тем, как вся веб-страница попадет в браузер посетителей, произойдет ряд вещей. Упрощенное представление — что-то вроде;

1. Входящий запрос : веб-сервер (обычно Apache) получает запрос на скрипт и «делегирует» работу ядру PHP (движку Zend). Если вы используете PHP как, скажем, модуль Apache, он уже загружен и готов к действию. Если вы используете PHP в качестве исполняемого файла CGI, он должен сначала «свернуть», прежде чем он сможет выполнить какую-либо работу.

2. Подготовьте OPCODE : механизм считывает, анализирует и компилирует скрипт в «OPCODE» (список инструкций о том, что делать, когда дело доходит до выполнения)

3. Выполнение : инструкции выполняются, и конечный результат (веб-страница) поступает в браузер посетителей.

4. Уничтожьте все : PHP-движок отбрасывает все; коды операций, переменные, хранящиеся в памяти, вывод — много. Вернуться к шагу 1 …

В A HOWTO есть более подробное объяснение по оптимизации PHP и очень подробное обсуждение в PHP Inside Out (PDF).

Я вернусь к OPCODE кешированию через минуту, но это общая картина.

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

Суть в том, что много отходов. Ваше приложение перерождается с каждым новым попаданием в скрипт.

Ленивый PHP
Таким образом, ясно, что чем меньше работы PHP-движка, тем быстрее посетитель получит запрашиваемую веб-страницу.

Но если у вас есть сложное приложение, предлагающее все виды функций, с использованием абстракции базы данных, веб-сервисов, аутентификации пользователей и т. Д., Как можно надеяться на приличную производительность?!?

Ответ лень : делать абсолютный минимум.

Например, зачем загружать все 1000 строк логики обработки ошибок, если не было ошибок для обработки? Зачем включать эту библиотеку из 101 функции, если только одна вызвана для текущего запроса? Зачем загружать всю таблицу в массив PHP, если вы собираетесь отображать только 10 записей одновременно? Зачем повторно отображать HTML, если содержимое не изменилось?

Хитрость в Lazy PHP заключается в том, чтобы разработать ваш код таким образом, чтобы у него был минимальный «отпечаток», необходимый для обслуживания текущего запроса, и «указатели» на то, где найти остальное, если это необходимо.

Ленивый Включает
Как правило, когда вы развертываете скрипт PHP на свой веб-сервер, он не будет меняться очень часто (только если вы замените его новой версией). Возвращаясь к четырем шагам, описанным выше, внезапно становится ясно, что подготовку OPCODE нужно выполнять только один раз для каждой версии скрипта PHP; в первый раз это выполнено.

Если вы используете какую-либо форму OPCODE-кэша, такую ​​как Zend Accelerator , PHP Accelerator или Turck MMCache (хорошо для пользователей Windows), вы можете пропустить шаг 2, после первого выполнения OPCODE кэшируются для будущего использования.

К сожалению, немногие из дешевых хостов LAMP, похоже, знают о кешировании OPCODE (или о том, что некоторые из них с открытым исходным кодом / бесплатны для использования), поэтому большинству из нас приходится мириться с расходами на чтение, анализ и компиляцию, которые идут с каждым скрипт PHP берет.

Один из удобных способов обойти это — аккуратное размещение команд, таких как include и require_once .

Например, что, если у вас есть система аутентификации, где вы хотите отслеживать неудачные попытки входа в систему. Возможно, у вас есть код что-то вроде;

isValid($_POST['username'],$_POST['password']) ) { // The user is valid } else { $message = "Invalid username / password for ". $_POST['username']." from ".$_SERVER['REMOTE_HOST']; $Logger->log($message); } ?> 

Регистратор загружается (и создается) при каждом запросе, но он используется только при неудачном входе в систему. Как насчет;

isValid($_POST['username'],$_POST['password']) ) { // The user is valid - the stuff here } else { // Now load the logger... require_once 'lib/logger.php'; $Logger = & new Logger('auth.log'); $message = "Invalid username / password for ". $_POST['username']." from ".$_SERVER['REMOTE_HOST']; $Logger->log($message); } ?>
isValid($_POST['username'],$_POST['password']) ) { // The user is valid - the stuff here } else { // Now load the logger... require_once 'lib/logger.php'; $Logger = & new Logger('auth.log'); $message = "Invalid username / password for ". $_POST['username']." from ".$_SERVER['REMOTE_HOST']; $Logger->log($message); } ?> 

Теперь регистратор включается только тогда, когда есть что-то, что требует регистрации.

Более того, вы можете включать функции и классы внутри функции, поэтому также возможно следующее:

actionAllowed($action) ) { // Update the article - store in DB for example } else { // Include a class require_once 'lib/logger.php'; $Logger = & new Logger ('useractions.log'); $message = "Illegal action: $action attempted by ". $User->username(); $Logger->log($message); } }
actionAllowed($action) ) { // Update the article - store in DB for example } else { // Include a class require_once 'lib/logger.php'; $Logger = & new Logger ('useractions.log'); $message = "Illegal action: $action attempted by ". $User->username(); $Logger->log($message); } } 

[Обратите внимание, что приведенный выше код не предназначен для предложения какой-либо конкретной стратегии регистрации / аутентификации]

Ленивые включения становятся особенно важными при написании OO PHP, где в вашем приложении могут быть сотни классов, все в отдельных файлах. Ограничение количества включаемых файлов только теми, которые фактически необходимы для обслуживания данного запроса, снижает накладные расходы.

Придать смысла?

[…продолжение следует…]