Предзагрузка

Начиная с PHP 7.4.0 разрешили настройку PHP на предварительную загрузку скриптов в память модуля opcache при запуске движка. Доступ к функциям, классам, интерфейсам или трейтам (но не константам) в этих файлах станет глобальным для всех запросов; файлы не потребуется включать явно. Предзагрузка повышает удобство и производительность за счёт постоянной доступности кода для очередных запросов, но увеличивает расход памяти. Одновременно с этим, изменения в предзагруженных скриптах вступят в силу только после перезагрузки PHP-процесса, которая очистит скрипты, которые предварительно загрузили. Поэтому предзагрузку скриптов выполняют только в производственном окружении, а не в среде разработки.

Баланс между ростом производительности и расходом памяти зависит от приложения. «Предзагрузка каждого файла» выглядит как простейшая стратегия, но такая стратегия полезна не в каждом сценарии. Предзагрузка полезна, только когда процесс не изменяется от запроса к запросу. Поэтому, хотя предзагрузка и работает в CLI-скрипте при включённом модуле opcache, это бесполезно. Исключение — предварительная загрузка библиотек FFI.

Замечание:

ОС Windows не поддерживает предзагрузку.

Настройка предзагрузки состоит из двух этапов и работает, только если включили модуль opcache. Сначала устанавливают значение для директивы opcache.preload в файле php.ini:

opcache.preload=preload.php

Файл preload.php — произвольный файл, который запустится один раз при старте сервера в режиме менеджера процессов PHP-FPM, Apache-модуля mod_php и т. д. и загрузит код в постоянную память. На серверах, которые перед переключением на непривилегированного пользователя системы запускаются от имени root-пользователя, или если PHP запускается от имени root, что делать не рекомендуют, пользователя системы для запуска предварительной загрузки указывают в директиве opcache.preload_user. Запуск предварительной загрузки от имени root по умолчанию запрещён. В файле конфигурации PHP устанавливают значение opcache.preload_user=root, чтобы явно разрешить такой запуск.

PHP проанализирует и загрузит в постоянную память каждый файл, который указали в выражениях include, include_once, require, require_once или в аргументе функции opcache_compile_file() в скрипте preload.php. В следующем примере загрузится каждый файл с расширением .php в директории src, если файл не содержат в названии части Test.

<?php

$directory
= new RecursiveDirectoryIterator(__DIR__ . '/src');
$fullTree = new RecursiveIteratorIterator($directory);
$phpFiles = new RegexIterator($fullTree, '/.+((?<!Test)+\.php$)/i', RecursiveRegexIterator::GET_MATCH);

foreach (
$phpFiles as $key => $file) {
require_once
$file[0];
}

?>

И выражение include, и функция opcache_compile_file() будут работать, но по-разному влияют на обработку кода.

  • Выражение include выполнит код в файле, а функция opcache_compile_file() — нет, поэтому только выражение включения файлов поддерживает условное объявление, при котором функции объявляют в блоках if.
  • Поскольку выражение include выполняет код, PHP также разберёт и предзагрузит объявления вложенных файлов, которые включили выражением include.
  • Функция opcache_compile_file() загружает файлы в произвольном порядке. Даже если в файле a.php определили класс A, а в файле b.php класс B, который наследует класс A, это не изменит порядок загрузки файлов и функция opcache_compile_file() всё равно загрузит файлы в случайном порядке. А выражение include первым обязательно загрузит файл a.php.
  • В любом случае, если более поздний скрипт включает файл, который загрузился прежде, то PHP всё равно выполнит содержимое файла, но не переопределит символы, которые в нём определили. Выражение include_once не предотвратит повторное включение файла. Иногда требуется загрузить файл снова, чтобы включить глобальные константы, которые определили в файле, поскольку они не обрабатываются предварительной загрузкой.
Поведение, которое ждут от кода, определяет, какой подход лучше. Для кода, который иначе использовал бы автозагрузчик, функция opcache_compile_file() даёт больше гибкости. С кодом, который иначе загружался бы вручную, часто надёжнее выражение include.