Усе починається з vendor/autoload.php. Цей файл піднімає Composer\Autoload\ClassLoader і реєструє його метод loadClass через spl_autoload_register. Далі PHP працює ліниво: поки код не згадав клас, нічого не підключається. Щойно інтерпретатор зустрічає невідоме імʼя, скажімо в new PhpUkraine\Hiring\Domain\Vacancy, він передає це повне імʼя зареєстрованим завантажувачам. Composer шукає в масиві PSR-4-правил найдовший префікс, що з ним збігається. Знайшовши, відрізає його, замінює зворотні слеші в залишку на /, додає .php і приклеює до базової теки. Виходить один конкретний шлях, який перевіряється через file_exists. Ніякого сканування й ніякого «пошуку по проєкту»: одне рядкове перетворення й одна перевірка.
Звідси й вимога, щоб неймспейс повторював структуру тек. Завантажувач обчислює шлях, а не розшукує файл десь на диску. Клас, оголошений як namespace PhpUkraine\Service; у файлі src/Services/Mailer.php, не буде знайдений ніколи, бо правило "PhpUkraine\\": "src/" дає шлях src/Service/Mailer.php. Найпідступніша версія цієї помилки - регістр. Імена класів у PHP регістронезалежні, тож локально на macOS чи Windows файл mailer.php спокійно віддається під імʼя Mailer, а на Linux-сервері та сама збірка падає з Class not found. Тому назва файла має точно збігатися з іменем класу, включно з великими літерами, а Vacancy.php і vacancy.php варто вважати різними файлами навіть тоді, коли ваша файлова система так не вважає.
Classmap вирішує іншу задачу. Composer будує таблицю під час dump-autoload: обходить перелічені теки, розбирає файли токенайзером, запамʼятовує, у якому файлі оголошено який клас, і кладе результат у vendor/composer/autoload_classmap.php. Пошук перетворюється на звертання до масиву. Розплата за це - статичність: файл, доданий після дампу, у карті не зʼявиться. Тому classmap тримають для коду, який PSR-4 у принципі не описує: міграції без неймспейсів, legacy з кількома класами в одному файлі, згенеровані файли з довільними іменами. Для нового коду він не потрібен.
На продакшені ці два механізми зводяться разом. composer install --no-dev --optimize-autoloader (він же -o) проходить PSR-4-теки й розгортає правила в classmap: тепер кожен клас проєкту й вендорів знаходиться за одне читання масиву замість склеювання шляху й file_exists на кожен неймспейс-кандидат. Оптимізація стосується лише пошуку файлів, а не швидкості самого коду, але на застосунку з півтори тисячею класів на запит різниця в кількості stat-викликів відчутна. Класи, яких у карті немає, все ще шукаються старим способом. Прибрати й цей фолбек можна через --classmap-authoritative: карта стає єдиною правдою, чого в ній немає - того не існує. Режим найшвидший і водночас найкрихкіший, тому на дев-машині його не вмикають, а на деплої карту обовʼязково перебудовують після кожної зміни коду.
Кілька місць, де спотикаються найчастіше. autoload-dev з Tests\ не потрапляє у продакшн-дамп при --no-dev, і це навмисно; саме тому забутий прапорець тягне тестові класи у веб. Секція files до автозавантаження взагалі не належить: перелічені файли підключаються одразу при завантаженні vendor/autoload.php, бо функції й константи spl_autoload_register не ловить. PSR-0 у composer.json ще зустрічається в старих пакетах, але офіційно оголошений застарілим, тож у своєму коді використовуйте лише PSR-4. І одне спостереження, яке економить години: під час оптимізованого дампу Composer 2 друкує does not comply with psr-4 autoloading standard. Skipping. для кожного класу з невідповідним неймспейсом. Це попередження в логах збірки - готовий список файлів, які зламаються на сервері, ще до того, як хтось відкриє сторінку.
// composer.json - чотири різні механізми в одній секції
{
"autoload": {
"psr-4": {
"PhpUkraine\\": "src/", // префікс закінчується на \, база - на /
"PhpUkraine\\Hiring\\": "src/Hiring/" // виграє найдовший збіг, не порядок
},
"classmap": ["database/migrations"], // сканується під час dump-autoload
"files": ["src/helpers.php"], // require на кожному запиті
"exclude-from-classmap": ["**/Fixtures/"]
},
"autoload-dev": {
"psr-4": { "Tests\\": "tests/" } // не потрапляє в dump з --no-dev
}
}
# Як резолвиться PhpUkraine\Hiring\Domain\Vacancy:
# найдовший збіг префікса -> "PhpUkraine\Hiring\" => src/Hiring/
# залишок імені класу -> Domain\Vacancy
# \ замінюється на /, плюс .php
# підсумковий файл -> src/Hiring/Domain/Vacancy.php
# файла немає -> завантажувач мовчить, PHP кидає Error: Class not found
# Продакшн-збірка: PSR-4-правила розгортаються в готову таблицю
composer install --no-dev --optimize-autoloader
# результат видно тут, разом з правилами, що реально задеплоєні
# vendor/composer/autoload_classmap.php
# vendor/composer/autoload_psr4.php
# Жорсткіший режим: карта - єдине джерело правди, stat-викликів немає зовсім
composer dump-autoload --classmap-authoritative
Скажіть коротку формулу: «PSR-4 - це рядкове перетворення імені класу на шлях, classmap - готова таблиця, а `-o` перетворює перше на друге». Далі згадайте регістр файлів на Linux і різницю між `-o` та `--classmap-authoritative`: саме ці дві деталі відрізняють людину, яка деплоїла, від людини, яка читала документацію.