Хабрахабр

[Перевод] Предварительная загрузка в PHP 7.4

Перевод данной статьи подготовлен специально для студентов курса «Backend разработчик на PHP».

4 добавлена предварительная загрузка — возможность, которая позволяет значительно повысить производительность кода. В PHP 7.

О предзагрузке в двух словах.

  • Для предварительной загрузки файлов вам потребуется написать отдельный PHP-скрипт.
  • Этот скрипт выполняется однократно при запуске сервера.
  • Все предварительно загруженные файлы доступны в памяти для всех запросов.
  • Изменения, внесенные в исходный файл, не подействуют, пока вы не перезапустите сервер.

Поговорим о новой возможности подробнее.

Больше, чем Opcache

Да, предварительная загрузка основывается на opcache, но это не совсем одно и то же. Opcache берет исходные файлы PHP, компилирует их в опкоды, после чего сохраняет скомпилированные файлы на диск.

Таким образом, opcache позволяет пропустить этап трансляции исходных файлов в то, что, собственно, и необходимо интерпретатору PHP во время выполнения. Опкоды можно считать низкоуровневым представлением вашего кода, которое легко интерпретируется во время выполнения. Заметная экономия!

Скомпилированные при помощи opcash файлы ничего не знают о других файлах. Тем не менее можно сэкономить еще больше. Кроме того, opcache проверяет, изменились ли исходные файлы, и при обнаружения изменений аннулирует их кэши. Если у вас есть класс А, являющийся расширением класса B, их все равно нужно будет связать во время выполнения.

Она сохраняет такой «скомпилированный» фрагмент исполняемого кода (то есть кода, который может использовать PHP-интерпретатор) в памяти. И тут на помощь приходит предварительная загрузка: она не только компилирует исходные файлы в опкоды, но и связывает зависимые классы, трейты и интерфейсы.

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

О каких же «частях кодовой базы» идет речь?

Предварительная загрузка на практике

Для корректной предварительной загрузки разработчик должен указать серверу, какие файлы нужно загрузить. Это делается с помощью простого PHP-скрипта, так что бояться нечего.

Ничего сложного.

  • Вы предоставляете скрипт предварительной загрузки и даете ссылку на него в вашем файле php.ini с помощью opcache.preload.
  • Каждый PHP-файл, который вы хотите предварительно загрузить, нужно передать в opcache_compile_file() из скрипта предварительной загрузки.

Допустим, вы хотите предварительно загрузить какой-нибудь фреймворк. Пусть это будет Laravel. В этом случае ваш скрипт должен просмотреть все PHP-файлы в директории vendor/laravel и добавить их поочередно.

Вот как вы можете подключить этот скрипт в php.ini:

opcache.preload=/path/to/project/preload.php

А вот пример реализации:

$files = /* Массив файлов, которые вы хотите предварительно загрузить */; foreach ($files as $file) { opcache_compile_file($file);
}

Вместо opcache_compile_file вы можете использовать include. Однако, похоже, здесь не обошлось без бага, так как на момент написания статьи второй вариант не сработал.

Предупреждение о невозможности предварительно загрузить несвязанный класс

Появилось предупреждение Can't preload unlinked class? Дело в том, что перед предзагрузкой файлов нужно также предварительно загрузить их зависимые объекты — интерфейсы, трейты и родительские классы.

Если возникнут какие-либо проблемы с зависимостями классов, то вас предупредят об этом при запуске сервера:

Can't preload unlinked class Illuminate\Database\Query\JoinClause: Unknown parent Illuminate\Database\Query\Builder

Обратите внимание, что opcache_compile_file() только распарсит файл, но не выполнит его. Это значит, что если у класса есть зависимости, которые не были предварительно загружены, то и сам класс не может быть предварительно загружен.

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

Делать это вручную — задача неблагодарная и трудоемкая, так что разработчики уже трудятся над автоматизированными решениями. Именно поэтому нужно внимательнее подбирать файлы для предварительной загрузки, чтобы избежать проблем с зависимостями.

Поддержка composer

Наиболее перспективное автоматизированное решение готовят разработчики composer, который уже используется в большинстве современных PHP-проектов.

Как и сама предварительная загрузка, эта функция все еще находится на стадии разработки. Сейчас ребята работают над возможностью настройки предварительной загрузки в composer.json, которая в свою очередь сгенерирует вместо вас файл предварительной загрузки. Следить за развитием событий можно здесь.
К счастью, вам не придется вручную настраивать файлы предварительной загрузки, если вы этого не хотите, — composer сможет сделать это за вас.

Требования к серверу

Есть еще два важных момента, о которых должен помнить разработчик при использовании предварительной загрузки.

Это значит, что если вы используете shared-хостинг, то не сможете настраивать PHP как вздумается. Вы уже знаете, что нужно создать запись в php.ini, чтобы предварительная загрузка сработала.

Имейте это в виду. На практике вам понадобится выделенный (виртуальный) сервер, чтобы оптимизировать предварительно загруженные файлы для отдельного проекта.

Для большинства это очевидно, но не будет лишним напомнить. Также помните, что вам нужно будет перезапускать сервер (если вы используете php-fpm, этого достаточно) каждый раз, когда вы захотите перезагрузить файлы в памяти.

Производительность

Теперь перейдем к самому важному вопросу: действительно ли предварительная загрузка повышает производительность?

Бен Морел (Ben Morel) поделился результатами сравнительного тестирования, которые можно найти в той же теме по composer, на которую мы ссылались выше. Разумеется!

При желании вы можете предварительно загрузить только так называемые hot classes — классы, которые часто используются в вашей кодовой базе. И еще, что интересно. В первом случае производительность повышается на 17 %, во втором — на 13 %. Тесты Бена Морела показывают, что загрузка всего около 100 таких классов обеспечивает более высокий рост производительности, чем предварительная загрузка всего сразу.

Разумнее всего для начала просто предварительно загрузить как можно больше. Разумеется, выбор классов для предварительной загрузки зависит от конкретного проекта. Если же вам так важны эти несколько процентов разницы в производительности, то придется контролировать код во время выполнения.

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

Эту функцию очень легко настроить на сервере при условии, что он находится в полном вашем распоряжении. Сейчас важно, что в composer будет добавлена поддержка предзагрузки, что избавит от необходимости самостоятельно создавать файлы для нее.

Будете ли вы использовать предварительную загрузку в новой версии PHP 7.4? Появились мысли или замечания? Напишите мне в Twitter или по электронной почте.

Традиционно ждем ваши комментарии и плюсы, если считаете статью интересной 🙂

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть