Все об автозагрузке в PHP



















PHP-программисту, использующему ООП, довольно часто требуется так организовать классы, чтобы определение каждого из них находилось в отдельном файле. В таком случае программист нередко сталкивается с довольно нудной задачей: подключением используемых
классов, которые используются в проекте. Чтобы автоматизировать данный процесс, в PHP 5.0 была предусмотрена возможность автозагрузки классов.



__autoload()


Начиная с версии PHP 5.0 была введена функция __autoload(). Способ работы ее совершенно прост: когда скрипт в коде натыкается на неизвестный ему класс, он вызывает функцию __autoload(),
при условии, что она была определена, и передает ей название неизвестного класса в надежде, что эта функция подключит файл с определением данного класса. Таким образом, в функции __autoload() следует
указать каким именно способом будет происходить поиск требуемых к подключению классов.




Пример:


Допустим, у нас есть несколько классов проекта в папке classes. Их названия и содержания таковы:


classes/MyClass1.php:


class MyClass1 {
public function __construct() {
echo "<p>executed MyClass1::__construct() method</p>";
}
}

classes/MyClass2.php:


class MyClass2 {
public function __construct() {
echo "<p>executed MyClass2::__construct() method</p>";
}
}

classes/MyClass3.php:


class MyClass3 {
public function __construct() {
echo "<p>executed MyClass3::__construct() method</p>";
}
}

В головном скрипте нам нужно организовать их автоматическую загрузку. Для этого в головном скрипте мы объявляем функцию автозагрузки которая ищет подключаемые классы в папке classes. После чего можно использовать эти классы:


index.php:


function __autoload($aClassName) {
$aClassFilePath = $_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'classes' . DIRECTORY_SEPARATOR . $aClassName . '.php';
if (file_exists($aClassFilePath)) {
echo "<p>executing __aturoload() with aClassName = {$aClassName}</p>";
require_once $aClassFilePath;
return true;
}
return false;
}

$obj1 = new MyClass1();
$obj2 = new MyClass2();
$obj3 = new MyClass3();

В результате на странице мы увидим такую картину:


executing __aturoload() with aClassName = MyClass1
executed MyClass1::__construct() method

executing __aturoload() with aClassName = MyClass2
executed MyClass2::__construct() method

executing __aturoload() with aClassName = MyClass3
executed MyClass3::__construct() method

Как видно из примера, у нас объявлено несколько классов в отдельных файлах, а в главном скрипте нет ни одного вызова инструкций include/require. Причем, автозагрузка классов происходит по мере необходимости.


Однако данный подход к решению проблемы выявил существенный недостаток: иногда требуется определять несколько функций автозагрузки, и тогда в функции __autoload() приходится городить некоторую логику
совмещения этих функций, что довольно неудобно. Вскоре был придуман более совершенный механизм автозагрузки классов.



Использование автозагрузки из библиотеки SPL


Начиная с версии PHP 5.1.2 была внедрена новая система автозагрузки классов, которая была включена в библиотеку SPL(Standard PHP Library). Основное отличие новой системы автозагрузки в том, что можно определять сколько угодно функций автозагрузки.
Все они формируют стек функций автозагрузки, в котором каждая последующая добавленная функция автозагрузки попадает в конец стека. Таким образом, при работе скрипта, когда он натыкается на неизвестный ему класс, он поочередно вызывает все функции
автозагрузки, находящиеся в стеке до тех пор, пока не будет загружен требуемый класс.


Так, новая система автозагрузки включает целых 6 функций управления автозагрузкой:




  • spl_autoload_call — принудительно загружает класс по его имени, используя все доступные в системе автозагрузчики;


  • spl_autoload_extensions — возвращает/модифицирует расширения файлов, из которых происходит загрузка неинициализированных классов;


  • spl_autoload_functions — возвращает список всех зарегистрированных автозагрузчиков в системе;


  • spl_autoload_register — регистрация собственного автозагрузчика в стеке автозагрузки;


  • spl_autoload_unregister — удаление автозагрузчика из стека автозагрузки;


  • spl_autoload — основная функция автоматической загрузки классов. Именно она вызывается при обращении к классу, который еще не инициализирован. Данная функция
    активирует все автоматические загрузчики из стека в порядке их добавления.


Чтобы включить способ автозагрузки по умолчанию, нужно лишь вызвать функцию spl_autoload_register() без каких-либо
параметров. После этого активизируется средство автозагрузки классов, которое автоматически вызывает функцию spl_autoload() при попытке создать в программе экземпляр неизвестного класса. В качестве
параметра этой функции передается имя неизвестного класса, которое впоследствии преобразуется в имя файла. Механизм таков: имя класса приводится к нижнему регистру, и к нему по очереди добавляются все стандартные расширения( сначала .inc, потом
.php ), после чего производится поиск файла в той же директории, где расположен скрипт, и найдя его, попытается загрузить содержимое этого файла, полагая, что в нем находится определение неизвестного класса. Также в реализации автозагрузки классов
по-умолчанию поддерживаются пространства имен, при этом имени пакета ставится в соответствие имя каталога. И все-таки в автозагрузке по-умолчанию слишком много ограничений. Поэтому практически всегда разработчики пишут свои функции автозагрузки
и добавляют их в стек.


Пример:


Допустим, у нас есть два различных(classes и lib) каталога, в котором хранятся некоторые классы, и для автозагрузку классов из каждого каталога мы хотим
сделать собственную функцию автозагрузки(исключительно в качестве примера).


classes/MyClass1.php:


class MyClass1 {
public function __construct() {
echo "<p>executed MyClass1::__construct() method</p>";
}
}

classes/MyClass2.php:


class MyClass2 {
public function __construct() {
echo "<p>executed MyClass2::__construct() method</p>";
}
}

classes/MyClass3.php:


class MyClass3 {
public function __construct() {
echo "<p>executed MyClass3::__construct() method</p>";
}
}

index.php:


//Сначала убедимся, что в стеке автозагрузки не зарегистрировано ниодной функции
var_dump(spl_autoload_functions());

//функция автозагруки, загружающая классы из папки classes:
function loadFromClasses($aClassName) {
$aClassFilePath = $_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'classes' . DIRECTORY_SEPARATOR . $aClassName . '.php';
if (file_exists($aClassFilePath)) {
echo "<p>executing __aturoload() with aClassName = {$aClassName}</p>";
require_once $aClassFilePath;
return true;
}
return false;
}

//функция автозагруки, загружающая классы из папки libs:
function loadFromLibs($aClassName) {
$aClassFilePath = $_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'libs' . DIRECTORY_SEPARATOR . $aClassName . '.php';
if (file_exists($aClassFilePath)) {
echo "<p>executing __aturoload() with aClassName = {$aClassName}</p>";
require_once $aClassFilePath;
return true;
}
return false;
}

//регистрируем обе функции автозагрузки
spl_autoload_register('loadFromClasses');
spl_autoload_register('loadFromLibs');

//Проверим, что в стеке функций автозагрузки присутствуют две функции:
var_dump(spl_autoload_functions());

$object1 = new MyClass1();
$object2 = new MyClass3();

//удалим первую функцию автозагрузки
spl_autoload_unregister('loadFromClasses');

//В стеке должна остаться одна функция:
var_dump(spl_autoload_functions());

$object3 = new MyClass2(); //здесь будет ошибка

В результате на странице получим:




boolean false 

array (size=2) 0 => string 'loadFromClasses' (length=15)                    1 => string 'loadFromLibs' (length=12) 

executing __aturoload() with aClassName = MyClass1

executed MyClass1::__construct() method


executing __aturoload() with aClassName = MyClass3

executed MyClass3::__construct() method


array (size=1) 0 => string 'loadFromLibs'                                        (length=12)

Fatal error: Class 'MyClass2' not found in Z:hometest.locwwwindex.php on line
44


Из примера можно видеть, что в скрипте зарегистрированы две функции автозагрузки, которые были поочередно вызваны. После чего из стека автозагрузки была удалена одна функция, и произведена попытка ее вызова, и, как следствие - скрипт выдал ошибку.



Переход с функции __autoload() на использование SPL-автозагрузки


В языки PHP функция __autoload() является устаревшей, поэтому в будущих версиях PHP поддержка этой функции не гарантируется. С использованием данной функции в проекте связана еще одна проблема - отключается
возможность использования SPL-автозагрузки. Чтобы не попасться в ситуацию, когда обнаружится, что функция __autoload() не вызывается PHP-интерпретатором, или в случае необходимости поддержки SPL-автозагрузки,
можно просто вызвать функцию spl_autoload_register() с переданной в качестве аргумента строкой "__autoload", как показано ниже:


spl_autoload_register("__autoload");


Вывод


Механизм автоматической загрузки классов - это еще один крайне востребованный инструмент в арсенале PHP-разработчика. Использование этого механизма встречается повсеместно: будь то код какого-либо небольшого проекта или новомодный фреймворк.
Понимание
механизма автозагрузки классов в php дает значительные преимущества освоившему ее разработчику. По большому счету задача внедрения функций автозагрузки - автоматизировать операцию повсеместного вызова инструкций require/include.
Конечно, также знание этих нюансов дает более глубокое познание о работе PHP-скриптов, знакомство с php-фреймворками будет происходить полее мягко и т.д.



Дополнительно


Сообщество PHP-разработчиков давно занимается стандартизацией того, как лучше всего организовать механизм автозагрузки, который бы использовался всеми остальными заинтересованными сторонами. Преследуется довольно банальная цель: чтобы при подключении
стороннего класса или фреймворка можно было быстро его внедрить в вашу автозагрузку и начать использовать как можно быстрее. Текущая спецификация, описывающая актуальный стандарт автозагрузки называется PSR-4.
Ее перевод доступен здесь.

3029   0  

Comments

    Ничего не найдено.