PSR-стандарты и автозагрузка: чек-лист перед продакшеном
Перед деплоем PHP-проекта проверяют не только тесты. Разбираем, какие PSR реально влияют на автозагрузку и продакшен, и собираем чек-лист, который ловит проблемы до того, как они дойдут до боевого сервера.

Композер-автозагрузка на локальной машине работает, тесты зелёные, а на продакшене класс App\Service\PaymentGateway не находится с ошибкой Class not found. Причина почти всегда одна: где-то нарушено соответствие между именем класса, пространством имён и путём к файлу — то есть PSR-4. Этот чек-лист — про то, что проверить перед деплоем, чтобы автозагрузчик не подвёл на сервере с чувствительной к регистру файловой системой.
Материал ориентирован на PHP 8.1+ и Composer 2.x. Формат — практический чек-лист: не пересказ спецификаций, а конкретные проверки, которые ловят реальные поломки. Внутренности PSR-стандартов разбирать не будем, только то, что влияет на автозагрузку и продакшен.
Какие PSR вообще про это
Из всей серии PSR к автозагрузке напрямую относятся два стандарта, а остальные влияют косвенно — через то, как оформлены файлы.
| Стандарт | О чём | Влияние на продакшен |
|---|---|---|
| PSR-4 | Соответствие пространства имён и пути к файлу | Прямое: ошибка ломает автозагрузку |
| PSR-0 | Старый автозагрузчик (устарел) | Только в легаси, новые проекты не используют |
| PSR-1 | Базовые требования к коду: один класс на файл, имена | Косвенное: нарушение мешает автозагрузке |
| PSR-12 | Оформление кода (заменил PSR-2) | Косвенное: на автозагрузку не влияет, но проверяется линтером |
PSR-0 объявлен устаревшим — deprecated. Если он ещё описан в вашем composer.json, это признак старого кода, который стоит перевести на PSR-4. Ниже речь идёт именно о PSR-4.
Что требует PSR-4 на практике
Правило одно: полное имя класса минус префикс пространства имён должно точно совпадать с путём к файлу относительно корневой директории — включая регистр каждой буквы. Класс App\Service\PaymentGateway при маппинге "App\\": "src/" обязан лежать в src/Service/PaymentGateway.php. Не paymentGateway.php, не Payment_Gateway.php.
Чек-лист перед деплоем
- Сгенерируйте оптимизированный автозагрузчик. Команда
composer dump-autoload --optimize --classmap-authoritativeстроит статическую карту классов. Флаг--optimize(или короткий-o) убирает поиск файла по файловой системе на каждом обращении. Флаг--classmap-authoritativeговорит автозагрузчику: чего нет в карте — того нет вообще, не искать на диске. - Проверьте маппинг в
composer.json. Секцияautoload.psr-4должна содержать актуальные префиксы. Каждый путь заканчивается слешем:"App\\": "src/", а не"src". - Прогоните проект на регистрозависимой ФС. На macOS и Windows файловая система по умолчанию нечувствительна к регистру:
User.phpиuser.php— один файл. На Linux-сервере это два разных файла. Класс, который грузился локально, на продакшене не найдётся. - Убедитесь, что установлены только продакшен-зависимости.
composer install --no-dev --optimize-autoloaderисключает пакеты изrequire-devи сразу строит оптимизированную карту. - Проверьте один класс на файл. PSR-1 требует, чтобы файл либо объявлял символы (классы, функции), либо выполнял побочные действия — но не то и другое сразу. Автозагрузчик находит файл по имени класса и ждёт этот класс внутри.
Флаг --classmap-authoritative — это не «ещё немного быстрее», а смена поведения: после него автозагрузчик перестаёт искать классы на диске. Любой класс, не попавший в карту при сборке, на проде просто не существует. Отлично для иммутабельного деплоя и катастрофа для кода, который генерирует классы на лету.Как проверить регистр до деплоя
Локальная macOS не поймает опечатку в регистре — файл найдётся в любом случае. Есть два надёжных способа проверить заранее.
Собрать образ и запустить в контейнере
Если деплой идёт через Docker с Linux-образом, соберите его локально и прогоните автозагрузку внутри. Регистрозависимая ФS контейнера сразу покажет проблему при первом же обращении к «потерянному» классу.
Валидатор composer.json
Команда ниже проверяет структуру и соответствие маппинга без развёртывания сервера:
# Composer 2.x
# Проверяет корректность composer.json и composer.lock
composer validate --strict
# Пересобирает автозагрузчик и покажет предупреждения,
# если класс не соответствует объявленному PSR-4 маппингу
composer dump-autoload --optimize 2>&1 | grep -i "does not comply"При несоответствии Composer выводит предупреждение вида Class App\Service\Payment located in ./src/service/Payment.php does not comply with psr-4 autoloading standard. Именно эту строку и ловит grep. Если вывод пустой — маппинг в порядке.
Если не находится класс
Три частых причины ошибки Uncaught Error: Class "..." not found на продакшене:
- Регистр в имени файла не совпадает с классом. Симптом: локально всё работает, на Linux-сервере — нет. Проверьте буквально каждую букву пути против полного имени класса.
- Забыли пересобрать автозагрузчик после деплоя. Новый класс есть в коде, но старая карта из
vendor/composer/autoload_classmap.phpо нём не знает. Симптом заметен при--classmap-authoritative. Решение:composer dump-autoload -oв конце деплоя. - Класс из
require-devпопал в продакшен-код. После--no-devего пакета вvendorнет. Симптом: класс из тестовой или dev-библиотеки не находится только на проде.
Быстрая диагностика
Проверить, знает ли автозагрузчик о конкретном классе, можно прямо в короткой проверке:
<?php
// проверка одной строкой: файл check-autoload.php в корне проекта
require __DIR__ . '/vendor/autoload.php';
$className = 'App\\Service\\PaymentGateway';
if (class_exists($className)) {
// покажет реальный путь к файлу, который нашёл автозагрузчик
$reflection = new ReflectionClass($className);
echo 'Найден: ' . $reflection->getFileName() . PHP_EOL;
} else {
echo 'Автозагрузчик не видит ' . $className . PHP_EOL;
}Запустите этот файл на самом продакшен-сервере (или в контейнере с той же ФС): php check-autoload.php. Если путь выводится с неожиданным регистром — вот и причина.
Что настроить в пайплайне
Ручной чек-лист хорош один раз, дальше его встраивают в CI. Минимальный набор проверок перед деплоем:
composer validate --strict— на этапе сборки, падает при рассинхронеcomposer.jsonиcomposer.lock;composer install --no-dev --optimize-autoloader— на шаге деплоя;- прогон тестов в контейнере с Linux-ФС, а не только на машине разработчика;
- линтер
PHP_CodeSnifferс набором правил PSR-12 — ловит нарушения оформления до ревью.
Следующий шаг после этого чек-листа — посмотреть на APCu-кеш автозагрузчика для долгоживущих процессов (например, под RoadRunner или Swoole), где даже оптимизированная классовая карта читается с диска только один раз, а дальше живёт в памяти. Инвалидация этого кеша при деплое — отдельная тема, здесь её не разворачиваем.
Тест и проверочная: Быстрые ответы с объяснением, почему остальные варианты неверны
Спросить за 10 ₽Источники: PSR-4: Autoloader — PHP-FIG, Composer: Autoloader Optimization
Частые вопросы
Чем --optimize отличается от --classmap-authoritative?
У меня локально всё работает, а на сервере класс не находится. Почему?
А если у меня Composer 1.x, а не 2.x?
Нужно ли использовать PSR-0 в новом проекте?
Что делать, если сборка автозагрузчика проходит, а класс всё равно не грузится в проде?
Влияет ли PSR-12 на автозагрузку?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.