Автоматическая загрузка классов через стандартную библиотеку PHP
4 сентября 2015
Документация по автозагрузке: https://www.php.net/manual/ru/language.oop5.autoload.php
Что бы не было путаницы, тут и далее под термином «элемент» будут пониматься классы, трейты и интерфейсы.
Фиксированное подключении элемента через require_once загружает файл в оперативную память и заставляет процессор обработать его содержимое. Если файлов не много, то в этом нет проблемы и можно использовать require_once.
Но когда число файлов уходит за пару десятков, то становится трудно контролировать, что бы подключались только используемые файлы. Ведь иначе оперативная память будет наполняться неиспользуемым кодом. Для длительного и объёмного проекта со множеством элементов удобно использовать подключение по факту надобности или другими словами — автоматическую загрузку. Это экономит внимание разработчика, оперативную память и процессорную нагрузку сервера.
Для создания автоматической загрузки элементов в стандартной библиотеке PHP используется функция spl_autoload_register($autoload, $throw=true, $prepend=false), которая добавляет функцию-обработчик в конец специальной очереди загрузок. Когда запрашиваемый элемент (класс, трейт, интерфейс) не найден, то начинается последовательный вызов обработчиков из очереди.
Аргументы функции spl_autoload_register($autoload, $throw=true, $prepend=false):
Документация https://www.php.net/manual/ru/function.spl-autoload-register.php
Интерфейс E находится в файле /module/aaa/bbb/e.php
Класс X находится в файле /module/aaa/bbb/x.php
Класс Y находится в файле /module/aaa/bbb/y.php
Вариант прямого подключения элементов:
Вариант подключения элементов с помощью автоматической загрузки:
В результате работы предыдущего скрипта на экран будет выведено:
Что бы не было путаницы, тут и далее под термином «элемент» будут пониматься классы, трейты и интерфейсы.
Фиксированное подключении элемента через require_once загружает файл в оперативную память и заставляет процессор обработать его содержимое. Если файлов не много, то в этом нет проблемы и можно использовать require_once.
Но когда число файлов уходит за пару десятков, то становится трудно контролировать, что бы подключались только используемые файлы. Ведь иначе оперативная память будет наполняться неиспользуемым кодом. Для длительного и объёмного проекта со множеством элементов удобно использовать подключение по факту надобности или другими словами — автоматическую загрузку. Это экономит внимание разработчика, оперативную память и процессорную нагрузку сервера.
Для создания автоматической загрузки элементов в стандартной библиотеке PHP используется функция spl_autoload_register($autoload, $throw=true, $prepend=false), которая добавляет функцию-обработчик в конец специальной очереди загрузок. Когда запрашиваемый элемент (класс, трейт, интерфейс) не найден, то начинается последовательный вызов обработчиков из очереди.
Аргументы функции spl_autoload_register($autoload, $throw=true, $prepend=false):
Документация https://www.php.net/manual/ru/function.spl-autoload-register.php
- callable $autoload — функция-обработчик. При вызове обработчика в первый параметр передаётся название требуемого элемента. Затем по названию в теле функции можно выполнить подключение файла с элементом;
- bool $throw — флаг срабатывания исключения, если обработчик не удалось добавить в очередь;
- bool $prepend — флаг добавления обработчика в начало очереди;
Пример использования
Рассмотрим случай подключения в скрипт одного интерфейса и двух классов.Интерфейс E находится в файле /module/aaa/bbb/e.php
namespace AAA\BBB;
interface E
{
public function write_str($str);
}
Класс X находится в файле /module/aaa/bbb/x.php
namespace AAA\BBB;
class X implements E
{
public $s = 'Тест 1';
public function write_str($str)
{
echo $str;
}
}
Класс Y находится в файле /module/aaa/bbb/y.php
namespace AAA\BBB;
class Y
{
public static $s = 'Тест 2';
}
Вариант прямого подключения элементов:
require_once($_SERVER['DOCUMENT_ROOT'].'/module/aaa/bbb/e.php'); //интерфейс E
require_once($_SERVER['DOCUMENT_ROOT'].'/module/aaa/bbb/x.php'); //класс X
require_once($_SERVER['DOCUMENT_ROOT'].'/module/aaa/bbb/y.php'); //класс Y
$a = new \AAA\BBB\X();
$a->write_str('Привет'); //выведет 'Привет'
echo '<br>';
echo \AAA\BBB\Y::$s; //выведет 'Тест 2'
Вариант подключения элементов с помощью автоматической загрузки:
spl_autoload_register(function($e_name){
//Выводим имя запрашиваемого элемента (класса, интерфейса, трейта)
echo $e_name.'<br>';
//Переводим имя в нижний регистр, т.к элементы, включая пространства имён, регистронезависимые,
//поэтому нужно приводить имена в единый вид
$e_name = mb_strtolower($e_name, 'utf-8');
//символ разделения директории \ пишем как \\, т.к символ экранируется в строках PHP
if(mb_strpos($e_name, 'aaa\\', 0, 'utf-8')===0)
{
$f_path = str_replace('\\', '/', $e_name);
require_once($_SERVER['DOCUMENT_ROOT'].'/module/'.$f_path.'.php');
}
});
//Используем псевдоним пространства имён для показа того, что при запросе элемента
//псевдоним в автозагрузчик не передаётся, а заменяется на оригинальное название пространства имён
use \AAA\BBB as DDD;
$a = new DDD\X();
$a->write_str('Привет'); //выведет 'Привет'
echo '<br>';
echo DDD\Y::$s; //выведет 'Тест 2'
В результате работы предыдущего скрипта на экран будет выведено:
AAA\BBB\X
AAA\BBB\E
Привет
AAA\BBB\Y
Тест 2
AAA\BBB\E
Привет
AAA\BBB\Y
Тест 2