Что такое автозагрузка; Как вы используете spl_autoload, __autoload и spl_autoload_register?


204

Я изучаю передовые стандарты PHP и пытаюсь реализовать новые и полезные методы. Ранее я использовал __autoloadтолько для того, чтобы избежать включения нескольких файлов на каждой странице, но недавно я увидел совет__autoload manual

spl_autoload_register () предоставляет более гибкую альтернативу для автозагрузки классов. По этой причине использование __autoload () не рекомендуется и может быть признано устаревшим или удалено в будущем.

но я действительно не могу понять, как реализовать spl_autoloadиspl_autoload_register

Ответы:


336

spl_autoload_register() позволяет вам зарегистрировать несколько функций (или статических методов из вашего собственного класса автозагрузки), которые PHP будет помещать в стек / очередь и вызывать последовательно при объявлении «нового класса».

Так, например:

spl_autoload_register('myAutoloader');

function myAutoloader($className)
{
    $path = '/path/to/class/';

    include $path.$className.'.php';
}

//-------------------------------------

$myClass = new MyClass();

В приведенном выше примере «MyClass» - это имя класса, который вы пытаетесь создать, PHP передает это имя в виде строки spl_autoload_register(), что позволяет вам выбрать переменную и использовать ее для «включения» соответствующего класса / файла. , В результате вам не нужно специально включать этот класс с помощью оператора include / require ...

Просто вызовите класс, для которого вы хотите создать экземпляр, как в примере выше, и, поскольку вы зарегистрировали собственную функцию (via spl_autoload_register()), которая будет определять, где находится весь ваш класс, PHP будет использовать эту функцию.

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

Пример:

spl_autoload_register('MyAutoloader::ClassLoader');
spl_autoload_register('MyAutoloader::LibraryLoader');
spl_autoload_register('MyAutoloader::HelperLoader');
spl_autoload_register('MyAutoloader::DatabaseLoader');

class MyAutoloader
{
    public static function ClassLoader($className)
    {
         //your loading logic here
    }


    public static function LibraryLoader($className)
    {
         //your loading logic here
    }

Что касается spl_autoload , руководство заявляет:

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

С практической точки зрения, если все ваши файлы расположены в одном каталоге, а ваше приложение использует не только файлы .php, но и пользовательские файлы конфигурации, например, с расширениями .inc, то одна из стратегий, которую вы могли бы использовать, - добавить каталог, содержащий все файлы к пути включения PHP (через set_include_path()).
И поскольку вам также требуются ваши файлы конфигурации, вы должны использовать spl_autoload_extensions()список расширений, которые вы хотите, чтобы PHP искал.

Пример:

set_include_path(get_include_path().PATH_SEPARATOR.'path/to/my/directory/');
spl_autoload_extensions('.php, .inc');
spl_autoload_register();

Поскольку spl_autoload является реализацией __autoload()магического метода по умолчанию , PHP вызовет spl_autoload, когда вы попытаетесь создать новый класс.

Надеюсь это поможет...


35
Это может быть одним из лучших ответов в истории ответов когда-либо. Респект. У меня был один из тех "OMG! Теперь все это имеет смысл!" моменты из-за тебя, мой хороший человек. Я думаю, что я мог бы просто открыть фан-клуб.
Просто Обычная Высокая

2
Чтобы сделать этот ответ лучшим из всех ответов, когда-либо даже в альтернативных вселенных, добавьте, что spl_autoload очень, хм, «услужливо» (?) Преобразует все имена файлов в нижний регистр (см. Мой комментарий к @user ниже). Не можете использовать spl_autoload_register () vanilla, если вам нравится ваш CapitalLettersAndStuff.
Просто Обычная Высокая

6
@ Just Plain High У меня нет этой проблемы, и все мои файлы классов верблюжьей. Кстати, это прекрасный ответ. Это помогло мне понять простую концепцию, которую я не мог понять, пока не прочитал этот пост! Мой включаемый файл из 85 (и растущий) строк, который включает все мои файлы классов, теперь состоит из 7 строк!
Кайл

2
Это действительно хороший ответ, но я упускаю одну вещь. Какова действительная функциональность по умолчанию? С классами, которые я знаю, он использует пространство имен в качестве пути и имя класса в качестве имени файла. Хотя я не могу понять, как это работает с функциями.
SiXoS

2
Разве это не одно из огромных преимуществ использования spl_autoload_register()__autoload()вообще) того, что ленивая загрузка включает файлы / классы? Это подразумевается ответом, но не указано явно. Для меня это важная информация, которая идеально подходит для включения в ваш ответ! :)
Риного

13

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

Чтобы продемонстрировать это поведение, просто создайте файл с именем index.php:

<?php
spl_autoload_register();
var_dump(new Main\Application);

Затем создайте папку с именем Main, расположенную прямо рядом с файлом index.php. Наконец, создайте файл с именем Application.php, расположенный в Main, и вставьте в него следующий код:

<?php namespace Main;
class Application{}

9
Примечание от моего возни со всем этим: spl_autoload () - и, следовательно, spl_autoload_register () - преобразует имена файлов в нижний регистр (несмотря на сообщения об ошибках, мольбы и яростное голосование). Это означает, что вы можете искать «Main \ Application», но spl_autoload ищет «main \ application». Если вы любите верблюдов, как я, вам придется написать свою собственную функцию. Существует пример хорошего стартера здесь: github.com/ircmaxell/PHP-CryptLib/blob/...
Just Plain High

1
Плюсы: spl_autoload_register () - самый быстрый метод автозагрузки. Минусы: он будет работать только с строчными файлами / классами, а также с пространствами имен, которые в наше время просто требуют большого времени (нет возможности указать, использовать ли CamelCase и т. Д.). Но если вы можете жить со структурой namespace / classname.php, не смотрите дальше.
Stamster

1
spl_autoload_register()Реализация по умолчанию не может найти унаследованные классы. Поэтому, используя значения по умолчанию, строчные файлы и каталоги, отражающие путь к пространству имен, все работает нормально, если у меня нет класса, который расширяет другой класс (родительский). Затем PHP выдает ошибку, что он не может найти этот родительский класс, даже если они все находятся в одном каталоге / пространстве имен! Что сбивает с толку, так это то, что буквально найдены только классы первого уровня, поэтому мне пришлось поместить другой spl_autoload_register()с правилом анонимной функции сразу после 1-го, чтобы вручную включить отсутствующие родительские / унаследованные классы.
Stamster

1

Вот как я использую автозагрузку. В данном примере я хочу загрузить классы из 3 разных каталогов.

function namespaceAutoload($rawClass){

$class = str_replace('\\', DIRECTORY_SEPARATOR, $rawClass);

$possiblePaths[] = '..\sys\class\file.php';
$possiblePaths[] = '..\sys\class\lib\file.php';
$possiblePaths[] = '..\sys\class\class.file.inc.php';

foreach ($possiblePaths as $templatePath) {
    $path = str_replace(["\\", "file"], [DIRECTORY_SEPARATOR, $class], $templatePath);
    if (file_exists($path)) {
        require_once "$path";
        break;
    }
} spl_autoload_register("namespaceAutoload"); 

В приведенном примере PHP будет искать пространство имен \ class в этих трех каталогах, используя эти три разных формата имени файла.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.