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

Composer предлагает четыре механизма автозагрузки: psr-4, psr-0, classmap и files. По умолчанию все шаблоны и большинство пакетов используют PSR-4, но это не значит, что он подходит везде. На проекте с сотнями классов неправильный выбор стоит миллисекунд на каждом запросе, а на легаси-коде с нестандартными именами файлов PSR-4 вообще не заработает. Разберём, чем эти варианты отличаются и когда что брать. Речь про Composer 2.x и PHP 8.x.
О чём вообще спор
Автозагрузка решает одну задачу: когда код обращается к App\Service\Payment, а этот класс ещё не подключён, интерпретатор должен найти файл и подключить его сам. Без автозагрузки пришлось бы вручную писать require на каждый класс.
PSR-4 и PSR-0 — это соглашения* о том, как имя класса преобразуется в путь к файлу. Classmap — прямая таблица «класс → файл», без всяких соглашений. Files — просто список файлов, которые подключаются всегда. Разница между ними не косметическая: она диктует, как вы раскладываете код по папкам и сколько стоит найти класс.
* PSR (PHP Standard Recommendation) — рекомендации, которые публикует группа PHP-FIG. PSR-0 (устарел) и PSR-4 описывают автозагрузку, но силы закона у них нет: их соблюдают, потому что так договорилось сообщество и так работает Composer.
PSR-4: текущий стандарт
PSR-4 связывает префикс пространства имён с базовой директорией. Настройка в composer.json выглядит так:
{
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
}
Класс App\Service\Payment ищется в файле src/Service/Payment.php. Префикс App\ отбрасывается, остаток превращается в путь. Имя файла точно совпадает с именем класса, включая регистр — на Linux это критично, на Windows ошибку не заметите до деплоя.
Ключевое отличие от PSR-0: базовая директория не повторяет весь неймспейс. Вам не нужна папка src/App/, достаточно src/.
PSR-0: наследие
PSR-0 официально помечен как deprecated ещё в 2014 году, но встречается в старых пакетах. Здесь весь неймспейс отражается в структуре папок, а в именах классов ещё поддерживаются подчёркивания как разделители директорий (наследие эпохи до неймспейсов).
{
"autoload": {
"psr-0": {
"App\\": "src/"
}
}
}
Тот же App\Service\Payment при PSR-0 ищется в src/App/Service/Payment.php — префикс не отбрасывается. Отсюда лишний уровень вложенности, который все ненавидели. Новый код на PSR-0 писать незачем.
Classmap: таблица без соглашений
Classmap сканирует указанные директории, находит все объявления классов и строит прямую карту. Соглашение об именах не нужно — файл может называться как угодно, содержать несколько классов, лежать где попало.
{
"autoload": {
"classmap": ["legacy/", "database/migrations/"]
}
}
Это спасение для легаси: старый код с файлами class.payment.inc.php и двумя классами в одном файле не лезет ни в один PSR. Плата — карту нужно перестраивать при добавлении класса: composer dump-autoload. Забыли — новый класс не находится.
Files: подключить безусловно
Секция files подключает перечисленные файлы на каждом запросе, до любого обращения к классам. Используется для файлов с функциями и константами, которые нельзя автозагрузить по имени класса.
{
"autoload": {
"files": ["src/helpers.php"]
}
}
Осторожно: каждый файл здесь — это безусловный require при инициализации автозагрузчика. Пять хелперов терпимо, полсотни — заметная нагрузка на старте.
Сравнение
| Критерий | PSR-4 | PSR-0 | classmap | files |
|---|---|---|---|---|
| Структура папок | без префикса | с полным префиксом | любая | любая |
| Один класс = один файл | да | да | не требуется | не требуется |
| Нужен dump после нового класса | нет | нет | да | да |
| Скорость поиска класса | вычисление пути | вычисление пути | прямая карта | всегда подключён |
| Статус | актуален | deprecated | актуален | актуален |
| Подходит для нового кода | да | нет | для генерённого | для функций |
Что при этом с производительностью
При PSR-4 автозагрузчик на каждый неизвестный класс вычисляет путь и проверяет, существует ли файл, — это обращение к файловой системе. Classmap отдаёт путь из готового массива в памяти, без проверок. На проекте с активным использованием классов разница набегает, но её обычно перекрывает главный инструмент — оптимизированный автозагрузчик.
Команда composer dump-autoload --optimize (флаг -o) сканирует все PSR-4 и PSR-0 директории и превращает их в один classmap. После этого поиск любого класса — обращение к массиву, а не к диску. Это то, что должно стоять на продакшене.
PSR-4 удобен разработчику: добавил класс — он сразу нашёлся. Classmap быстр интерпретатору. Оптимизированный автозагрузчик даёт и то, и другое: PSR-4 в разработке, classmap в проде — из одного конфига.
Для продакшена есть ещё --classmap-authoritative (-a): автозагрузчик считает, что классов вне карты не существует, и вообще не трогает файловую систему при промахе. Быстрее, но если класс не попал в карту — фатальная ошибка. Годится только когда весь код заведомо в classmap.
Когда что выбирать
- Новый проект или пакет — PSR-4, без вариантов. Один префикс на директорию
src/, дальше структура папок повторяет неймспейсы. - Легаси с нестандартными именами файлов — classmap на старые директории, PSR-4 на новый код. Их можно смешивать в одном
composer.json. - Хелперы, функции, глобальные константы — files. Их нельзя автозагрузить по имени класса, потому что класса нет.
- PSR-0 — только если тащите старый пакет, который иначе не подключить. В своём коде — никогда.
Что ломается на практике
- Регистр в имени файла.
Payment.phpиpayment.php— на macOS и Windows одно и то же, на Linux разные файлы. Класс работает локально и падает на сервере сClass not found. Имя файла обязано совпадать с именем класса посимвольно. - Забыли dump после нового класса в classmap. Класс есть, файл на месте, а автозагрузчик его не видит. Лечится
composer dump-autoload. - Неоптимизированный автозагрузчик на проде. Каждый промах PSR-4 — обращение к диску. На высоконагруженном сервисе это лишняя работа под нагрузкой. Ставьте
-oв CI при сборке артефакта. - Несоответствие неймспейса и папки. Класс объявлен как
App\Service\Payment, а лежит вsrc/Services/Payment.php(лишняяs). PSR-4 требует точного соответствия — файл не найдётся.
Что сделать дальше
Проверьте, чем собирается автозагрузчик в вашем деплое. Если в пайплайне стоит просто composer install без --optimize, добавьте флаг для продакшен-сборки — это одна строка, а промахи по диску исчезнут. Легаси-директории переведите на classmap и не пытайтесь причёсывать их под PSR-4 сразу: смешанный конфиг легален. Спецификацию PSR-4 стоит прочитать целиком один раз — она короткая, и большинство вопросов про регистр и структуру папок закрываются именно там.
Логотип и фирменный стиль: Три концепции разного характера, палитра с обоснованием, проверка на читаемость в малом размере и в один цвет.
Спросить за 60 ₽Источники: PSR-4: Autoloader — PHP-FIG, Composer — Autoloading (docs)
Частые вопросы
У меня Composer 1.x, а не 2.x — всё то же самое?
Добавил класс, а он не находится — что проверять первым?
Можно ли смешивать PSR-4 и classmap в одном проекте?
--classmap-authoritative ускорит прод, но чем рискую?
Нужен ли dump-autoload на локальной разработке при PSR-4?
Почему код работает на моём Mac, но падает на сервере?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.