Ответ
Файл 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, сильно зависящих от времени инициализации фреймворка.
Ответ 18+ 🔞
Слушай, а вот эта штука с preload.php — это вообще огонь, если ты на PHP 7.4+ и с OPcache. Представь себе: ты каждый раз при запросе грузишь всю эту хуйню — фреймворк, автолоадер, сотни классов. А можно один раз, при старте PHP-FPM, взять и засунуть всё это в память, уже скомпилированное. И потом просто исполнять, без лишней ебалы с компиляцией и автозагрузкой. Красота же!
Ну и нахуя это надо, спросишь? А нахуя — чтобы не тратить время на одно и то же при каждом запросе в твоём Symfony или Laravel. Особенно если нагрузка овердохуища. Всё уже готово лежит, бери и работай.
Вот смотри, как это примерно выглядит в preload.php:
<?php
// preload.php
if (!function_exists('opcache_compile_file')) {
return; // Если OPcache выключен — иди нахуй, нечего тут делать
}
// 1. Автолоадер Composer — основа основ, его первым делом
$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. Свой собственный код из /src — все 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
Но, чувак, есть нюансы, ёпта! Без них никуда:
- Память жрёт как не в себя. Всё, что ты предзагрузил, будет висеть в памяти до перезапуска PHP-FPM. Так что не надо туда всю свою кодобазу пихать, а то накроется медным тазом твой сервак. Выбирай только самое ядро, самое частое.
- Кэш не обновится сам. Поменял код в предзагруженном файле? Перезапускай PHP-FPM, иначе нихуя не увидишь. OPcache такую срань сам не перечитает.
- С динамическими именами классов — нихуя не выйдет. Если класс создаётся через
$className = 'App\' . $name;, то его предзагрузить нельзя. Только статичный, нормальный код.
Если всё правильно настроить, то прирост на API, которые сильно зависят от инициализации фреймворка, может быть 10-30%. Не хило, да? Главное — не переборщить, а то будет тебе хиросима вместо оптимизации.