Об автозагрузке в PHP
При написании приложений, код размещают в отдельных файлах. Чтобы код одного файла использовать в другом, его необходимо подключить через функцию require_once или include_once
Времена до автозагрузки
До PHP 5.0 (2005 г.) использовались подключение файлов через многократные вызовы фукнций require_once
require_once __DIR__ . '/A.php';
require_once __DIR__ . '/B.php';
require_once __DIR__ . '/C.php';
В определенный момент придумали механизм автоматического подключения классов при первом обращении - автозагрузку. Первой реализацией был метод __autoload
Магический метод __autoload
Данный метод объявлен УСТАРЕВШИМ начиная с PHP 7.2.0 и его использование крайне не рекомендовано.
В коде необходимо было реализовать функцию __autoload
, которая вызывается в момент обращения к неизвестному классу. Ей будет передано в качестве аргумента название неизвестного класса. Соответственно __autoload()
должна подключит файл с определением нужного класса.
function __autoload($classname) {
$filename = "./". $classname .".php";
require_once($filename);
}
$a = new A();
$b = B::methodG();
$c = class_exists('C');
Уже при этом подходе здравый смысл подсказывал, что в одном файле должен находится один класс, а название класса должно совпадать с названием файла.
Стандартная функция __autoload()
имеет ряд существенных недостатков:
- нет возможности регистрации нескольких автозагрузчиков
- нет возможности динамически активировать/деактивировать автозагрузчики
В PHP 5.1.2 (2006 г.) эти проблемы решили через фукнции автозагрузчики.
Автозагрузка через spl_autoload_register
PHP позволяет зарегистрировать любое число функций-автозагрузчиков с помощью функции spl_autoload_register. В случае обращения к несуществующему в данный момент классу, PHP будет вызывать по очереди все зарегистрированные автозагрузчики, передавая им имя класса. Если автозагрузчик знает, где лежит этот класс, он должен подключить файл с ним, PHP увидит, что класс появился, и продолжит выполнение программы. Иначе PHP вызовет следующий автозагрузчик. Если ни один автозагрузчик не подключит файл с классом, то будет выведена ошибка об обращении к несуществующему классу.
function libraryOne($classname) {
$filename = "./path/one/". $classname .".php";
require_once($filename);
}
function libraryTwo($classname) {
$filename = "../../path/two/". $classname .".php";
require_once($filename);
}
// регистрация
spl_autoload_register('libraryOne');
spl_autoload_register('libraryTwo');
...
// деактивация первой библиотеки
spl_autoload_unregister('libraryOne');
Если подключается сторонняя библиотека, то она может зарегистрировать свой автозагрузчик для загрузки своих классов. Таким образом, каждая библиотека может устанавливать свои правила для поиска файлов со своими классами.
Есть fallback для __autoload
:
spl_autoload_register("__autoload");
Автозагрузка через composer и PSR-4
Дальше - лучше
Развитием идеи в одном файле один класс стал стандарт PSR-0 (англ.) (устаревший) и его развитие PSR-4 (англ.). PSR-4 говорит как надо называть классы, чтобы по полному имени класса узнать путь к файлу (чтобы потом его подключил автозагрузчик).
\<NamespaceName>(\<SubNamespaceNames>)*\<ClassName>
Например класс Library\A\B\C
следует помещать в файл Library/A/B/C.php
. Надо понимать, что это лишь рекомендация, PHP не требует, чтобы имя класса совпадало с именем файла, а неймспейсы с именами папок. Но следование PSR-4 освобождает от написания своего автозагрузчика, можно взять готовый.
Пример пакета foo-bar
по PSR-4
# namespace Foo\Bar
/path/to/packages/foo-bar/
src/
Baz.php # Foo\Bar\Baz
Qux/
Quux.php # Foo\Bar\Qux\Quux
tests/
BazTest.php # Foo\Bar\BazTest
Qux/
QuuxTest.php # Foo\Bar\Qux\QuuxTest
На сегодняшний день большинство PHP разработчиков пользуются загручиком из менеджера зависимостей Сomposer. Composer не является только лишь генератором автозагрузчика. Задачи, которые он выполняет намного шире.
Генерация и использование автозагрузчика из composer
В конфигурационном файле composer.json в разделе autoload необходимо указать корневой namespace проекта и корневую папку. Неймспейсы должны оканчиваться \\
, чтобы избежать конфликтов. Например просто Foo
будет соответствовать классам в пространстве FooBar
, а вот Foo\\
и FooBar\\
уже различны.
Пример раздела в файле composer.json говорящий, что классы из namespace'a Foo находятся в папке src, а классы из App\Plugins надо искать в plugins/.
{
"autoload": {
"psr-4": {
"Foo\\ ": "src/",
"App\\Plugins\\": "plugins/"
}
}
}
Соответственно классы будут искаться так:
Foo\Baz -> src/Baz.php
Foo\Bar\Baz -> src/Bar/Baz.php
Foo\Bar\BazTest -> src/Bar/BazTest.php
App\Plugins\Some\Class -> plugins/Some/Class.php
После добавления информации в composer.json, надо выполнить команду гененрирации загрузчика
php composer.phar dump-autoload
или при установленном composer
composer dump-autoload
Команда сгенерирует файлы автозагрузчика и положит их в папку vendor. После этого надо подключить автозагрузчик в свои файлы и наслаждаться программированием.
require_once __DIR__ . '/vendor/autoload.php';
Таким образом, следование PSR-4 и использование composer позволяет не писать свой автозагрузчик.
Почитать: