Composer и автозагрузка PSR-4
Своих книг библиотеке всегда мало. Нужной книги нет на полках — библиотекарь заказывает её в другой библиотеке, и через пару дней она стоит у вас.
С кодом то же самое. Запись в журнал, отправка писем, работа с датами — всё это уже написано и выложено другими разработчиками в виде пакетов.
Копировать чужие файлы вручную неудобно: у пакета бывают свои зависимости, у них свои, и всё это нужно держать в совместимых версиях. Эту работу делает Composer — менеджер зависимостей PHP: программа, которая скачивает пакеты проекта вместе со всем, что им нужно.
Composer ставит пакеты
Composer запускают в терминале, в папке проекта. Laravel Herd ставит его вместе с PHP, а в Linux его устанавливают отдельно, как описано в разделе «Подготовка компьютера» на странице курса:
$ composer init
$ composer require monolog/monologПервая команда задаёт несколько вопросов и создаёт файл composer.json — список того, что нужно проекту. Вторая находит пакет Monolog для записи журналов в каталоге пакетов Packagist, скачивает его и дописывает в composer.json. После неё в проекте лежат:
composer.json— что проекту нужно: имена пакетов и допустимые версии;composer.lock— какие версии установлены на самом деле;- папка
vendor/— скачанные пакеты и файлvendor/autoload.php.
В vendor/ окажется не только monolog, но и psr: Monolog сам зависит от пакета psr/log, и Composer скачал его без вашей просьбы.
Папку vendor/ не правят руками и не сохраняют в git — хранилище истории кода. Собрать vendor/ заново всегда можно командой composer install. А composer.json и composer.lock в git сохраняют.
composer.lock: install и update
composer.lock хранит точные версии всего установленного — и ваших пакетов, и их зависимостей. composer install читает этот файл и ставит ровно то, что в нём записано, поэтому у коллеги и на сервере окажется тот же код. composer update заново подбирает свежие версии в пределах composer.json и переписывает lock-файл. Эту команду запускают, когда сами решили обновить пакеты.
Автозагрузка по PSR-4
Composer загружает не только чужие классы, но и ваши. Автозагрузка — это механизм, который подключает файл класса сам, в момент, когда класс понадобился. Это помощник библиотекаря: по полному имени класса он находит полку и нужную книгу.
Правило, по которому имя класса превращается в путь к файлу, задают в composer.json:
{
"require": {
"monolog/monolog": "^3.12"
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
}Секция autoload говорит: всё, что начинается с App\, лежит в папке src/. В JSON обратная косая черта удваивается, как в PHP-строке 'App\\', а в самом имени она одна.
Такое правило превращения имени класса в путь называется PSR-4. Для класса App\Http\Kernel оно работает так:
- Префикс
App\заменяется папкойsrc/, от имени остаётсяHttp\Kernel. - Каждая
\становится/: получаетсяsrc/Http/Kernel. - В конце добавляется
.php:src/Http/Kernel.php.
Значит, класс лежит в файле src/Http/Kernel.php, а сам файл объявляет пространство имён, которое совпадает с папкой:
<?php
namespace App\Http;
class Kernel
{
public function handle(): string
{
return 'ok';
}
}После правки секции autoload запустите composer dump-autoload: Composer перестроит автозагрузчик. Точка входа, файл index.php, подключает один-единственный файл — require __DIR__ . '/vendor/autoload.php';. Дальше new App\Http\Kernel() работает без всякого require: автозагрузчик найдёт src/Http/Kernel.php сам.
PSR-4 — один из стандартов PSR, о которых договорились авторы популярных PHP-проектов; PSR-12 из того же ряда описывает оформление кода.
Что происходит в момент new
vendor/autoload.php регистрирует функцию-автозагрузчик через spl_autoload_register. Когда PHP встречает класс, которого ещё нет, он не сдаётся сразу: сначала вызывает эту функцию с полным именем класса. Функция находит и подключает файл, класс появляется — и new продолжается.
В программе ниже класс объявлен прямо внутри автозагрузчика: так весь пример умещается в одном файле, хотя Composer подключил бы класс из отдельного. Нажмите «Следующий шаг» и следите, в какой момент появляется строка load App\User.
1<?php2 3namespace App;4 5spl_autoload_register(function ($name) {6 echo 'load ', $name, "\n";7 class User8 {9 public string $role = 'guest';10 }11});12 13$u = new User();14echo $u->role, "\n";
Всё, что объявлено в этом файле, получает приставку App\.
Что стоит запомнить после виджета:
- автозагрузчик вызывается в момент
new, когда класса ещё нет, и получает полное имяApp\User, а неUser; - второй
new User()его уже не позовёт: класс объявлен, и искать нечего; - строка
use App\Models\User;автозагрузчик не вызывает: она только сокращает имя.
Как PHP находит классы без require — частый вопрос на собеседовании. Ответ: он вызывает зарегистрированный автозагрузчик с полным именем класса, а автозагрузчик Composer превращает имя в путь по правилу PSR-4.
Здесь картинка с библиотекарем неточна. Настоящий библиотекарь заказывает книгу, когда вы попросили, а Composer работает только до запуска программы. Пока программа выполняется, ничего не скачивается: всё уже лежит в vendor/.
Частая ошибка
Пространство имён в файле не совпадает с его папкой:
<?php
namespace App; // ✗
class Kernel
{
public function handle(): string
{
return 'ok';
}
}Fatal error: Uncaught Error: Class "App\Http\Kernel" not foundФайл лежит в src/Http/Kernel.php, но объявляет класс App\Kernel. По имени App\Http\Kernel автозагрузчик находит и подключает этот файл, а нужного класса в нём нет. Пространство имён должно повторять путь от src/: namespace App\Http;.
Главное
composer requireскачивает пакет со всеми зависимостями вvendor/; папкуvendor/в git не сохраняют, аcomposer.jsonиcomposer.lockсохраняют.composer installставит версии изcomposer.lock, аcomposer updateподбирает новые и переписывает его.- PSR-4 превращает
App\Http\Kernelвsrc/Http/Kernel.php: префикс меняется на папку,\на/, в конце.php. - PHP вызывает автозагрузчик с полным именем класса в момент первого
new, аvendor/autoload.phpподключают один раз.