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

Начиная с 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.
`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open