Для чего нужен файл preload.php в PHP?

«Для чего нужен файл preload.php в PHP?» — вопрос из категории PHP Core, который задают на 24% собеседований PHP Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Файл preload.php — это скрипт, используемый в связке с OPcache (начиная с PHP 7.4) для механизма предзагрузки (preloading). Его цель — скомпилировать и загрузить в память OPcache определенный набор PHP-файлов (классы, функции, скрипты) еще до запуска любого приложения на этом экземпляре PHP-FPM. Это превращает их из байт-кода в готовые к исполнению структуры данных в общей памяти, что исключает этап компиляции и автозагрузки при каждом запросе.

Какую проблему это решает на практике? В высоконагруженном Symfony/Laravel приложении каждый запрос тратит время на загрузку фреймворка, его компонентов и основных классов приложения через Composer autoload. Preloading делает это один раз при старте PHP-FPM.

Пример preload.php для Symfony-приложения:

<?php
// preload.php
if (!function_exists('opcache_compile_file')) {
    return; // Выходим, если OPcache не активирован
}

// 1. Предзагрузка ядра фреймворка и Composer autoloader
$vendorPath = __DIR__ . '/vendor/';
opcache_compile_file($vendorPath . 'autoload.php');

// 2. Предзагрузка часто используемых компонентов Symfony
$symfonyFiles = [
    $vendorPath . 'symfony/http-foundation/Request.php',
    $vendorPath . 'symfony/http-kernel/HttpKernel.php',
    $vendorPath . 'symfony/dependency-injection/Container.php',
];
foreach ($symfonyFiles as $file) {
    if (file_exists($file)) {
        opcache_compile_file($file);
    }
}

// 3. Предзагрузка собственных классов приложения (например, всех Entity и основных Services)
$appFiles = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(__DIR__ . '/src/'));
foreach ($appFiles as $file) {
    if ($file->isFile() && $file->getExtension() === 'php') {
        opcache_compile_file($file->getRealPath());
    }
}

Конфигурация в php.ini:

opcache.enable=1
opcache.preload=/var/www/myapp/preload.php
opcache.preload_user=www-data

Важные нюансы из опыта:

  • Потребление памяти: Все предзагруженные классы остаются в памяти OPcache до его перезапуска. Необходимо тщательно подбирать файлы для preload, чтобы не исчерпать память.
  • Инвалидация кэша: При обновлении кода предзагруженных файлов необходимо перезапустить PHP-FPM (или сервер), чтобы изменения вступили в силу, так как OPcache не перезагрузит эти файлы автоматически.
  • Динамические классы: Классы, имена которых определяются во время выполнения (например, через переменные), не могут быть предзагружены. Preloading наиболее эффективен для стабильного, часто используемого кода ядра приложения.

В результате правильной настройки preloading давал мне прирост производительности на 10-30% для API-endpoints, сильно зависящих от времени инициализации фреймворка.