Автозагрузка классов в PHP и PSR-0 Standard

Написана 11 Февраля, 2012 в 12:39. Автор: borN_free   |   Теги: autoloading, spl, psr-0 Комментарии 0

PHP AutoloadingДавайте условимся, что имеется файл Rectangle.php, содержащий определение класса Rectangle. Перед тем, как создать объект класса в любом месте проекта, вам необходимо подключить файл Rectangle.php, примерно так:





require "Rectangle.php";
$rect = new Rectangle(42, 25)

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

В этой статье мы пройдем через "историю" автозагрузки, со старых стандартов до PSR-0, который используется в таких PHP фреймворках как Lithium, Symfony, Zend и т.д.

Большинство примеров из начала данной статьи лишь демонстрационные, и в настоящее время являются deprecated. Их нельзя использовать в ваших проектах. Рекомендуется писать автозагрузчик по стандарту PSR-0.

Старый способ автозагрузки

В PHP5 мы можем использовать функцию __autoload(), которая автоматически вызывается когда ваш код ссылается на еще не подключенный класс. Функция предоставляет последний шанс для загрузки описания класса перед тем, как PHP выкинет Fatal Error.

Небольшой пример использования функции:

function __autoload($className) {
    $filename = $className . ".php";
    if (is_readable($filename)) {
        require $filename;
    }
}

Хорошим стилем является наличие проверки существования файла, перед его подключением, но иногда файл может существовать, а права будут запрещать его чтение, поэтому лучше использовать функцию is_readable(), которая проверяет оба условия.

Большим недостатком функции __autoload() является то, что вы можете написать только один автозагрузчик. В PHP 5.1.2 с помощью функции spl_autoload() мы можем зарегестрировать множество функций автозагрузки.

Функция spl_autoload_register() дает программисту возможность создавать цепочки автозагрузки (autoload chain) - серия функций которые могут быть вызваны для попытки загрузить класс или интерфейс. Пример:

function autoloadModel($className) {
    $filename = "models/" . $className . ".php";
    if (is_readable($filename)) {
        require $filename;
    }
}

function autoloadController($className) {
    $filename = "controllers/" . $className . ".php";
    if (is_readable($filename)) {
        require $filename;
    }
}

spl_autoload_register("autoloadModel");
spl_autoload_register("autoloadController");

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

Важно запомнить, что как только функция зарегистрирована с помощью spl_autoload_register(), функция __autoload() никогда не будет вызвана. Если вы хотите все-таки ее вызвать, то необходимо зарегестрировать как и любую другую функцию с помощью spl_autoload_register().

Очевидно, что вышеописанные функции очень просты и в реальных проектах реализация значительно сложнее.

Перед тем как поддержка пространств имен (namespace) была введена в PHP 5.3, разработчики придумывали собственные соглашения для предотвращения конфликтов имен. Согласно стандарту PEAR слова в именах классов разделялись нижним подчеркиванием, что соответствовало пути к папке/файлу: класс Zend_Translate, таким образом, находится в Zend/Translate.php. Автозагрузчик в этом случае должен заменять нижние подчеркивания на DIRECTORY_SEPARATOR для того, чтобы загрузить файл.

Так же разработчики придумывали различные способоы наименования файлов, например .php, .class.php, .inc. Некоторые библиотеки могут находится в различных папках. Автозагрузчику необходимо просматривать различные места, что бы загрузить все. Пример:

function __autoload($className) {
    $extensions = array(".php", ".class.php", ".inc");
    $paths = explode(PATH_SEPARATOR, get_include_path());
    $className = str_replace("_" , DIRECTORY_SEPARATOR, $className);
    foreach ($paths as $path) {
        $filename = $path . DIRECTORY_SEPARATOR . $className;
        foreach ($extensions as $ext) {
            if (is_readable($filename . $ext)) {
                require_once $filename . $ext;
                break;
           }
       }
    }
}

Автозагрузка это отличная идея, но которая нуждалась в четкой стандартизации.

PSR-0 Standard

После появления namespace, группа людей из PHP сообщества решили создать PSR-0 стандарт, содержащий различные соглашения, которых необходимо придерживаться:
1. Пространство имен и класс должны иметь следующую структуру: \Vendor Name\(Namespace)*\Class Name.
2. Каждое пространство имен должно иметь корневое пространство имен - “Vendor Name”.
3. Каждое пространство имен может содержать сколько угодно вложенных.
4. Разделитель пространств имен конвертируется в DIRECTORY_SEPARATOR.
5. Каждое нижнее подчеркивание в названиях пространств имен конвертируется в DIRECTORY_SEPARATOR.
6. Файл должен иметь расширение .php
7. Названия пространств имен могут содержать буквы и цифры, нижнее подчеркивание, могут быть написаны в любом регистре.

Согласно стандарту PSR-0, в структуре папок будет корневая с именем “Vendor Name”, потом папка пространства имен (сколько угодно большая вложенность), и непосредственно файл с классом.

PHP Autoloading

namespace Vendor\Package;
class Example
{
}

Таким образом, определение для \Doctrine\Common\Connections может быть найдено по пути /path/to/project/lib/Doctrine/Common/Connections.php.

Вы можете использовать загрузчики PHP фреймворков Symfony, Pear2, AuraPHP (PHP 5.4+) и т.д.

by phpmaster.com

Оставьте свой комментарий:

Поля с * обязательны.