4 minutes to read, 8.46K views since 2017.01.06 Читати українською Read in english

Автозагрузка классов

Подключение других файлов в вашем сценарии

Когда вы пишете программу, которая состоит из более чем одного файла вам необходимо include или require файлы в другой с помощью

include 'filename.php'; 
require 'another.php'; 

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

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

<?php

include_once 'some/library.php'; // SomeLibrary class

if ($userLogged) {
  $lib = new SomeLibrary();
  // do some stuff
} else {
  redirect_to('/');
}

В этом сценарии  файл some/library.php будет всегда анализироваться PHP и есть оперативную память и процессорное время, даже если пользователь не вошел в систему и перенаправляется на главную страницу сайта.

Таким образом, используя явное включение файлов не всегда является оптимальным решением. Конечно, вы можете включить вашу библиотеку только в том случае если пользователь залоглен на сайте:

<?php

if ($userLogged) {
  include_once 'some/library.php'; // SomeLibrary class
  $lib = new SomeLibrary();
  // do some stuff
} else {
  redirect_to('/');
}

Автоматическая загрузка недостающих файлов

Ручная загрузка зависимых файлов это хорошо, конечно, но это не всегда выглядит елегантно, согласитесь. На самом деле, php имеет способность включать файлы автоматически: есть магическая функция которая вызываеться когда клас, используемый в скрипте не был найден в текущей области видимости. Это делается с помощью spl_autoload_register:

spl_autoload_register(function ($class) {
    // this function would be called when php would not find some $class 
});

Вы должны установить функцию автозагрузки в начале вашего приложения и забыть о включении файлов после этого момента. Spl_autoload_register принимает один параметр - функцию, которая должна вызываться, когда какой-то класс не найден. Ее параметр $class  будет иметь значение имя класса (включая пространство имен) который не был найден:

"\Catchmetech\AutoloadingLesson\ExampleController"

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

Лучшая практика ( PSR) говорит, что пространство имен должно соответствовать папкам и каждый класс должен быть в отдельном файле. Так, класс в приведенном выше примере должен находиться в папке Catchmetech\AutoloadingLesson и должен быть назван ExampleController.php. Конечно, каждый класс должен использовать пространство имен, как я уже упоминал в предыдущих уроках :)

Итак, как определить, какой файл я должен включить в моей функции автозагрузки? С помощью str_replace заменим nemaspace разделители $class с правильным для нашей операционной системы DIRECTORY_SEPARATOR, добавим расширение файла и вуаля:

$fileName = str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';

Хорошо, у нас есть путь к файлу, но он относительный, так как мы использовали неймспейс класса для этого дела. Мы должны добавить к этому пути префикс $baseDir который должен соответствовать абсолютному пути к каталогу, где лежит наше приложение. Если вы правильно назвали классы и файлы - все будет работать

$baseDir = __DIR__.'/'; 
$fileName = $baseDir.$fileName;

Кроме того, мы можем проверить, есть ли файл, который мы ищем действительно существует в файловой системе посредством is_file, и если нет - выкидаем иксепшн:

spl_autoload_register(function ($class) {
    $base_dir = __DIR__.'/';

    $file = $base_dir . str_replace('\\',DIRECTORY_SEPARATOR, $class) . '.php';
    if (file_exists($file)) {
        require $file;
    } else {
        throw new \Exception ('can\'t include '.$file.PHP_EOL.' when trying to load `'.$class.'`');
    }
});

Вот и все, мы сделали автоматический загрузчик классов! Поместите код в верхней части загрузочного файла вашего приложения и забудьте о кучи include в файлах!

Read next article Working with relational database in php in course Basic PHP