ClassLoader.php в Cotonti

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

Файл ClassLoader.php в контексте системы Cotonti CMF является частью автозагрузчика классов, реализованного в рамках Composer. Он находится в директории /lib/vendor/composer/ и отвечает за управление автозагрузкой классов и интерфейсов в проекте.

Основное назначение и место в системе Cotonti:

ClassLoader.php реализует механизм автозагрузки, который позволяет динамически загружать классы и интерфейсы по мере их использования, без необходимости вручную подключать файлы с классами через require или include. Он интегрирован с системой Composer, которая управляет зависимостями и помогает организовать правильную загрузку классов из различных пространств имен (namespaces) или классов, использующих стандарты PSR-4 и PSR-0.

Взаимодействие внутри сайта:

Этот файл взаимодействует с основной логикой Cotonti через систему автозагрузки классов. Когда Cotonti пытается использовать какой-либо класс, который ещё не был загружен, механизм автозагрузки срабатывает и находит соответствующий файл с классом, включая его в работу. Важнейший аспект — это то, что все классы, зарегистрированные с помощью автозагрузчика, загружаются только при необходимости, что улучшает производительность и экономит ресурсы. ClassLoader.php управляет этим процессом.

Методы, функции и их назначение:

  1. Метод addPsr4:

    • Назначение: Регистрация новых путей для поиска классов в соответствии с форматом PSR-4.
    • Как работает: Метод добавляет один или несколько директорий для заданного префикса пространства имен (namespace). Это позволяет системе находить соответствующие файлы классов по указанным путям. Можно добавлять пути либо в начало, либо в конец списка, в зависимости от флага.
  2. Метод set:

    • Назначение: Регистрация путей для PSR-0.
    • Как работает: Этот метод добавляет или заменяет директории для заданного префикса, используя стандарт PSR-0. Это старый стандарт автозагрузки, который, однако, всё ещё используется в некоторых проектах и библиотеках.
  3. Метод setPsr4:

    • Назначение: Регистрация путей для PSR-4.
    • Как работает: Метод работает аналогично методу set, но для стандарта PSR-4. Он перезаписывает все пути для пространства имен, если они уже были зарегистрированы.
  4. Метод setUseIncludePath:

    • Назначение: Включение или выключение поиска классов в пути включения.
    • Как работает: Этот метод позволяет указать, следует ли искать классы в стандартном пути включения PHP (например, используя include_path).
  5. Метод getUseIncludePath:

    • Назначение: Проверка, активирован ли поиск классов в пути включения.
    • Как работает: Возвращает флаг, указывающий, используется ли текущий путь для включения файлов классов.
  6. Метод setClassMapAuthoritative:

    • Назначение: Установить флаг, указывающий, что карты классов должны быть авторитетными.
    • Как работает: Если флаг установлен, то система не будет пытаться искать классы в других путях, если они не указаны в карте классов.
  7. Метод getApcuPrefix:

    • Назначение: Возвращает префикс для кеширования с помощью APCu, если используется кеширование.
    • Как работает: Метод проверяет, включен ли расширение APCu, и если оно включено, возвращает префикс, который используется для кеширования файлов классов.
  8. Метод register:

    • Назначение: Регистрация автозагрузчика в глобальной системе автозагрузки PHP.
    • Как работает: Этот метод добавляет текущий автозагрузчик в стек автозагрузки с помощью spl_autoload_register. Это позволяет системе автоматически загружать классы, когда они требуются.
  9. Метод unregister:

    • Назначение: Отмена регистрации автозагрузчика.
    • Как работает: Метод удаляет автозагрузчик из стека с помощью spl_autoload_unregister.
  10. Метод loadClass:

  • Назначение: Загрузка класса.
  • Как работает: Когда вызывается метод для загрузки класса, этот метод проверяет, существует ли соответствующий файл и включает его.
  1. Метод findFile:
  • Назначение: Поиск пути до файла класса.
  • Как работает: Этот метод проверяет несколько стратегий поиска для нахождения файла класса, включая поиск по картам классов, стандартам PSR-4 и PSR-0, а также проверку через кеш APCu, если он используется.
  1. Метод findFileWithExtension:
  • Назначение: Поиск файла с указанным расширением.
  • Как работает: Это вспомогательный метод, который помогает найти файл класса, добавляя к его пути соответствующее расширение, такое как .php или .hh (для HHVM).
  1. Метод initializeIncludeClosure:
  • Назначение: Инициализация замыкания для безопасного включения файлов.
  • Как работает: Если замыкание ещё не инициализировано, оно создается, чтобы гарантировать, что файлы будут включены с ограниченным доступом к переменным и методам объекта (предотвращая использование $this и self в этих файлах).

Суть содержания кода и выполняемые задачи:

Основной задачей ClassLoader.php является обеспечение эффективной и гибкой автозагрузки классов и интерфейсов, удовлетворяя стандартам PSR-0 и PSR-4. Это позволяет системе Cotonti динамически загружать необходимые файлы с классами, не тратя время на предварительное подключение каждого файла вручную. Файл также поддерживает кеширование с помощью APCu, что ускоряет процесс загрузки классов.

Ключевыми условиями, которые обрабатывает этот файл, являются:

  • Управление поиском классов в разных пространствах имен.
  • Работа с картами классов для ускоренного поиска.
  • Использование нескольких стандартов автозагрузки (PSR-4 и PSR-0).
  • Кеширование результатов для повышения производительности.
  • Возможность регистрации и отмены регистрации автозагрузчика.

Таким образом, ClassLoader.php является важной частью инфраструктуры Cotonti, обеспечивая бесперебойную работу с классами и интерфейсами, что критически важно для работы всех компонентов фреймворка.

 

/*
 * This file is part of Composer.
 *
 * (c) Nils Adermann <[email protected]>
 *     Jordi Boggiano <[email protected]>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
// Комментарии с авторскими правами и лицензией, указывающие, что этот файл является частью Composer и предоставляется согласно лицензии, находящейся в файле LICENSE.

namespace Composer\Autoload; // Определение пространства имен для этого класса, указание, что этот класс принадлежит автозагрузчику Composer.

class ClassLoader // Начало определения класса ClassLoader, который отвечает за автозагрузку классов по стандартам PSR-0, PSR-4 и с использованием classmap.
{
    /** @var \Closure(string):void */
    private static $includeFile; // Статическая переменная для хранения анонимной функции (Closure), которая используется для включения файлов. Этот метод может быть настроен динамически.

    /** @var string|null */
    private $vendorDir; // Переменная экземпляра класса, которая может содержать путь к директории с установленными пакетами (vendor). Может быть пустой.

 

    // PSR-4
    /**
     * @var array<string, array<string, int>>
     */
    private $prefixLengthsPsr4 = array(); // Переменная для хранения длин префиксов в соответствии с PSR-4, где ключ - это префикс, а значение - массив с длинами.

    /**
     * @var array<string, list<string>>
     */
    private $prefixDirsPsr4 = array(); // Переменная для хранения директорий для префиксов по стандарту PSR-4. Для каждого префикса будет список директорий.

    /**
     * @var list<string>
     */
    private $fallbackDirsPsr4 = array(); // Переменная для хранения резервных директорий, которые будут использоваться в случае отсутствия класса в основных директориях PSR-4.

    // PSR-0
    /**
     * List of PSR-0 prefixes
     *
     * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
     *
     * @var array<string, array<string, list<string>>>
     */
    private $prefixesPsr0 = array(); // Переменная для хранения префиксов по стандарту PSR-0, структурированная по первой букве префикса, с путями для каждого префикса.

    /**
     * @var list<string>
     */
    private $fallbackDirsPsr0 = array(); // Переменная для хранения резервных директорий, которые будут использоваться в случае отсутствия класса по стандарту PSR-0.

    /** @var bool */
    private $useIncludePath = false; // Переменная для указания, нужно ли использовать include_path для поиска классов.

    /**
     * @var array<string, string>
     */
    private $classMap = array(); // Переменная для хранения отображений классов в массиве, где ключ - это имя класса, а значение - путь к файлу.

    /** @var bool */
    private $classMapAuthoritative = false; // Переменная, указывающая, является ли класс мапа авторитетным (надежным).

    /**
     * @var array<string, bool>
     */
    private $missingClasses = array(); // Переменная для отслеживания отсутствующих классов, где ключ - имя класса, а значение - булево значение.

    /** @var string|null */
    private $apcuPrefix; // Переменная для хранения префикса для использования с APCu кешем (если используется).

    /**
     * @var array<string, self>
     */
    private static $registeredLoaders = array(); // Статическая переменная для хранения зарегистрированных загрузчиков классов, где ключ - это имя загрузчика, а значение - экземпляр класса.

 

    /**
     * @param string|null $vendorDir
     */
    public function __construct($vendorDir = null) // Конструктор класса, принимающий необязательный параметр $vendorDir, который указывает директорию поставщика.
    {
        $this->vendorDir = $vendorDir; // Устанавливает значение параметра $vendorDir в свойство объекта $vendorDir.
        self::initializeIncludeClosure(); // Вызывает статический метод для инициализации замыкания для включения файлов.
    }

 

    /**
     * @return array<string, list<string>>
     */
    public function getPrefixes() // Метод для получения всех префиксов PSR-0.
    {
        if (!empty($this->prefixesPsr0)) { // Проверяет, не пустой ли массив префиксов PSR-0.
            return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); // Если префиксы PSR-0 существуют, объединяет их в один массив и возвращает.
        }

        return array(); // Если префиксы PSR-0 пусты, возвращает пустой массив.
    }

 

    /**
     * @return array<string, list<string>>
     */
    public function getPrefixesPsr4() // Метод для получения всех префиксов PSR-4.
    {
        return $this->prefixDirsPsr4; // Возвращает массив префиксов для PSR-4, ассоциированный с директориями.
    }

    /**
     * @return list<string>
     */
    public function getFallbackDirs() // Метод для получения всех fallback директорий для PSR-0.
    {
        return $this->fallbackDirsPsr0; // Возвращает массив директорий fallback для PSR-0.
    }

    /**
     * @return list<string>
     */
    public function getFallbackDirsPsr4() // Метод для получения всех fallback директорий для PSR-4.
    {
        return $this->fallbackDirsPsr4; // Возвращает массив директорий fallback для PSR-4.
    }

    /**
     * @return array<string, string> Array of classname => path
     */
    public function getClassMap() // Метод для получения карты классов.
    {
        return $this->classMap; // Возвращает карту классов с ключом в виде имени класса и значением — пути к файлу.
    }

    /**
     * @param array<string, string> $classMap Class to filename map
     *
     * @return void
     */
    public function addClassMap(array $classMap) // Метод для добавления новой карты классов.
    {
        if ($this->classMap) { // Проверяет, есть ли уже существующая карта классов.
            $this->classMap = array_merge($this->classMap, $classMap); // Если карта классов существует, объединяет текущую и новую карту.
        } else {
            $this->classMap = $classMap; // Если карты классов нет, устанавливает новую.
        }
    }

 

    /**
     * Регистрирует набор директорий PSR-0 для заданного префикса, либо
     * добавляя в начало, либо в конец ранее заданных директорий для этого префикса.
     *
     * @param string              $prefix  Префикс
     * @param list<string>|string $paths   Корневые директории PSR-0
     * @param bool                $prepend Нужно ли добавить директории в начало
     *
     * @return void
     */
    public function add($prefix, $paths, $prepend = false) // Метод для регистрации PSR-0 директорий для указанного префикса.
    {
        $paths = (array) $paths; // Преобразует $paths в массив, если это не массив, для удобства дальнейшей работы.

        if (!$prefix) { // Если префикс не задан (например, глобальные директории).
            if ($prepend) { // Если нужно добавить директории в начало массива.
                $this->fallbackDirsPsr0 = array_merge(
                    $paths, // Добавляем новые директории в начало массива.
                    $this->fallbackDirsPsr0 // Сохраняем существующие директории после новых.
                );
            } else { // Если нужно добавить директории в конец массива.
                $this->fallbackDirsPsr0 = array_merge(
                    $this->fallbackDirsPsr0, // Сохраняем старые директории на первом месте.
                    $paths // Добавляем новые директории в конец.
                );
            }

            return; // Завершаем выполнение метода, так как префикс не был задан.
        }

        $first = $prefix[0]; // Берем первую букву префикса для дальнейшего поиска в массиве.

        if (!isset($this->prefixesPsr0[$first][$prefix])) { // Если для данного префикса еще не существует списка директорий.
            $this->prefixesPsr0[$first][$prefix] = $paths; // Регистрируем новый префикс с соответствующими директориями.

            return; // Завершаем выполнение метода, так как префикс был успешно зарегистрирован.
        }

        if ($prepend) { // Если нужно добавить директории в начало уже существующего списка для префикса.
            $this->prefixesPsr0[$first][$prefix] = array_merge(
                $paths, // Добавляем новые директории в начало текущих.
                $this->prefixesPsr0[$first][$prefix] // Оставляем старые директории после новых.
            );
        } else { // Если нужно добавить директории в конец уже существующего списка для префикса.
            $this->prefixesPsr0[$first][$prefix] = array_merge(
                $this->prefixesPsr0[$first][$prefix], // Сохраняем старые директории в начале.
                $paths // Добавляем новые директории в конец.
            );
        }
    }

 

    /**
     * Регистрирует набор директорий PSR-4 для заданного пространства имен, либо
     * добавляя в начало, либо в конец ранее заданных директорий для этого пространства имен.
     *
     * @param string              $prefix  Префикс/пространство имен, с завершающим '\\'
     * @param list<string>|string $paths   Основные директории PSR-4
     * @param bool                $prepend Нужно ли добавить директории в начало
     *
     * @throws \InvalidArgumentException
     *
     * @return void
     */
    public function addPsr4($prefix, $paths, $prepend = false) // Метод для регистрации PSR-4 директорий для указанного пространства имен.
    {
        $paths = (array) $paths; // Преобразует $paths в массив, если это не массив, для удобства дальнейшей работы.

        if (!$prefix) { // Если префикс не задан (например, для корневого пространства имен).
            // Регистрируем директории для корневого пространства имен.
            if ($prepend) { // Если нужно добавить директории в начало массива.
                $this->fallbackDirsPsr4 = array_merge(
                    $paths, // Добавляем новые директории в начало массива.
                    $this->fallbackDirsPsr4 // Сохраняем старые директории после новых.
                );
            } else { // Если нужно добавить директории в конец массива.
                $this->fallbackDirsPsr4 = array_merge(
                    $this->fallbackDirsPsr4, // Сохраняем старые директории на первом месте.
                    $paths // Добавляем новые директории в конец.
                );
            }
        } elseif (!isset($this->prefixDirsPsr4[$prefix])) { // Если для данного префикса еще не зарегистрированы директории.
            // Регистрируем директории для нового пространства имен.
            $length = strlen($prefix); // Определяем длину префикса для использования в дальнейшем.
            if ('\\' !== $prefix[$length - 1]) { // Проверка, что префикс заканчивается на символ разделителя пространства имен.
                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); // Если не заканчивается, выбрасываем исключение.
            }
            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; // Сохраняем длину префикса для дальнейшего использования.
            $this->prefixDirsPsr4[$prefix] = $paths; // Регистрируем директории для данного префикса.
        } elseif ($prepend) { // Если директории для данного пространства имен уже зарегистрированы и нужно добавить их в начало.
            // Добавляем новые директории в начало существующего списка для префикса.
            $this->prefixDirsPsr4[$prefix] = array_merge(
                $paths, // Новые директории.
                $this->prefixDirsPsr4[$prefix] // Старые директории.
            );
        } else { // Если директории для данного пространства имен уже зарегистрированы и нужно добавить их в конец.
            // Добавляем новые директории в конец существующего списка для префикса.
            $this->prefixDirsPsr4[$prefix] = array_merge(
                $this->prefixDirsPsr4[$prefix], // Старые директории.
                $paths // Новые директории.
            );
        }
    }

 

   /**
     * Регистрирует набор директорий PSR-0 для заданного префикса,
     * заменяя все ранее заданные для этого префикса.
     *
     * @param string              $prefix Префикс
     * @param list<string>|string $paths  Основные директории PSR-0
     *
     * @return void
     */
    public function set($prefix, $paths) // Метод для регистрации наборов директорий PSR-0 с заменой предыдущих.
    {
        if (!$prefix) { // Если префикс не задан (для корневого пространства имен).
            $this->fallbackDirsPsr0 = (array) $paths; // Присваиваем новые директории для корневого пространства имен.
        } else { // Если префикс задан.
            $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; // Присваиваем новые директории для указанного префикса.
        }
    }

    /**
     * Регистрирует набор директорий PSR-4 для заданного пространства имен,
     * заменяя все ранее заданные для этого пространства имен.
     *
     * @param string              $prefix Префикс/пространство имен, с завершающим '\\'
     * @param list<string>|string $paths  Основные директории PSR-4
     *
     * @throws \InvalidArgumentException
     *
     * @return void
     */
    public function setPsr4($prefix, $paths) // Метод для регистрации наборов директорий PSR-4 с заменой предыдущих.
    {
        if (!$prefix) { // Если префикс не задан (для корневого пространства имен).
            $this->fallbackDirsPsr4 = (array) $paths; // Присваиваем новые директории для корневого пространства имен.
        } else { // Если префикс задан.
            $length = strlen($prefix); // Определяем длину префикса.
            if ('\\' !== $prefix[$length - 1]) { // Проверяем, что префикс заканчивается на разделитель пространства имен.
                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); // Если не заканчивается, выбрасываем исключение.
            }
            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; // Сохраняем длину префикса.
            $this->prefixDirsPsr4[$prefix] = (array) $paths; // Присваиваем новые директории для указанного префикса.
        }
    }

 

    /**
     * Включает поиск файлов классов в пути включения.
     *
     * @param bool $useIncludePath
     *
     * @return void
     */
    public function setUseIncludePath($useIncludePath) // Метод для включения поиска в пути включения.
    {
        $this->useIncludePath = $useIncludePath; // Устанавливает значение флага, указывающего на использование пути включения.
    }

    /**
     * Может быть использован для проверки, использует ли автозагрузчик путь включения для поиска классов.
     *
     * @return bool
     */
    public function getUseIncludePath() // Метод для получения текущего значения флага использования пути включения.
    {
        return $this->useIncludePath; // Возвращает текущее состояние флага.
    }

    /**
     * Отключает поиск классов в префиксах и запасных директориях, которые не были зарегистрированы в карте классов.
     *
     * @param bool $classMapAuthoritative
     *
     * @return void
     */
    public function setClassMapAuthoritative($classMapAuthoritative) // Метод для включения/выключения использования карты классов.
    {
        $this->classMapAuthoritative = $classMapAuthoritative; // Устанавливает значение флага, указывающего на авторитетность карты классов.
    }

 

    /**
     * Должен ли поиск класса завершаться ошибкой, если класс не найден в текущей карте классов?
     *
     * @return bool
     */
    public function isClassMapAuthoritative() // Метод для проверки, является ли карта классов авторитетной.
    {
        return $this->classMapAuthoritative; // Возвращает текущий статус флага авторитетности карты классов.
    }

    /**
     * Префикс APCu для кэширования найденных/не найденных классов, если расширение включено.
     *
     * @param string|null $apcuPrefix
     *
     * @return void
     */
    public function setApcuPrefix($apcuPrefix) // Метод для установки префикса APCu для кэширования.
    {
        $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; // Устанавливает префикс APCu, если расширение APCu включено, иначе null.
    }

    /**
     * Префикс APCu в использовании, или null, если кэширование APCu не включено.
     *
     * @return string|null
     */
    public function getApcuPrefix() // Метод для получения текущего префикса APCu.
    {
        return $this->apcuPrefix; // Возвращает префикс APCu или null, если кэширование не включено.
    }

 

    /**
     * Регистрирует этот экземпляр как автозагрузчик.
     *
     * @param bool $prepend Нужно ли добавлять автозагрузчик в начало списка
     *
     * @return void
     */
    public function register($prepend = false) // Метод для регистрации автозагрузчика.
    {
        spl_autoload_register(array($this, 'loadClass'), true, $prepend); // Регистрирует метод loadClass как автозагрузчик с приоритетом в зависимости от $prepend.

        if (null === $this->vendorDir) { // Проверка, если директория vendor не задана.
            return; // Если директория не задана, метод завершается.
        }

        if ($prepend) { // Если необходимо добавить в начало списка зарегистрированных автозагрузчиков.
            self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; // Добавляет текущий автозагрузчик в начало списка.
        } else { // Если автозагрузчик добавляется в конец списка.
            unset(self::$registeredLoaders[$this->vendorDir]); // Удаляет текущий автозагрузчик из списка (если он уже был).
            self::$registeredLoaders[$this->vendorDir] = $this; // Добавляет текущий автозагрузчик в конец списка.
        }
    }

 

    /**
     * Отменяет регистрацию этого экземпляра как автозагрузчика.
     *
     * @return void
     */
    public function unregister() // Метод для отмены регистрации автозагрузчика.
    {
        spl_autoload_unregister(array($this, 'loadClass')); // Отменяет регистрацию метода loadClass как автозагрузчика.

        if (null !== $this->vendorDir) { // Проверка, если директория vendor задана.
            unset(self::$registeredLoaders[$this->vendorDir]); // Удаляет текущий автозагрузчик из списка зарегистрированных.
        }
    }

    /**
     * Загружает указанный класс или интерфейс.
     *
     * @param  string    $class Имя класса
     * @return true|null Возвращает true, если класс был загружен, иначе null
     */
    public function loadClass($class) // Метод для загрузки класса.
    {
        if ($file = $this->findFile($class)) { // Если файл, соответствующий классу, найден.
            $includeFile = self::$includeFile; // Получение функции для включения файла.
            $includeFile($file); // Включение файла, который содержит класс.

            return true; // Возвращает true, если файл был успешно загружен.
        }

        return null; // Возвращает null, если файл не был найден.
    }

 

    /**
     * Находит путь к файлу, в котором определён класс.
     *
     * @param string $class Имя класса
     *
     * @return string|false Путь к файлу, если найден, иначе false
     */
    public function findFile($class) // Метод для поиска пути к файлу, содержащему класс.
    {
        // Поиск в карте классов
        if (isset($this->classMap[$class])) { // Если класс найден в классовой карте.
            return $this->classMap[$class]; // Возвращает путь к файлу из карты классов.
        }
        if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { // Если карта классов авторитетная или класс уже был определён как отсутствующий.
            return false; // Возвращает false, если класс не найден.
        }
        if (null !== $this->apcuPrefix) { // Если задан префикс для кэширования APCu.
            $file = apcu_fetch($this->apcuPrefix.$class, $hit); // Ищет путь к файлу в кэше APCu.
            if ($hit) { // Если файл найден в кэше.
                return $file; // Возвращает путь к файлу из кэша.
            }
        }

        $file = $this->findFileWithExtension($class, '.php'); // Ищет файл с расширением .php.

        // Ищет файлы Hack, если используется HHVM
        if (false === $file && defined('HHVM_VERSION')) { // Если файл с расширением .php не найден и запущен HHVM.
            $file = $this->findFileWithExtension($class, '.hh'); // Ищет файл с расширением .hh.
        }

        if (null !== $this->apcuPrefix) { // Если задан префикс для кэширования APCu.
            apcu_add($this->apcuPrefix.$class, $file); // Добавляет путь к файлу в кэш APCu.
        }

        if (false === $file) { // Если файл не найден.
            // Запоминает, что этот класс не существует.
            $this->missingClasses[$class] = true; // Отмечает класс как отсутствующий.
        }

        return $file; // Возвращает путь к файлу, если найден, иначе false.
    }

 

    /**
     * Возвращает текущие зарегистрированные загрузчики, индексированные по их соответствующим каталогам поставщиков.
     *
     * @return array<string, self> Массив зарегистрированных загрузчиков с ключами — директории поставщиков.
     */
    public static function getRegisteredLoaders() // Статический метод для получения списка всех зарегистрированных загрузчиков.
    {
        return self::$registeredLoaders; // Возвращает массив зарегистрированных загрузчиков.
    }

 

    /**
     * Находит путь к файлу, где определён класс, с учётом расширения.
     *
     * @param  string $class Имя класса
     * @param  string $ext   Расширение файла, например, '.php'
     * @return string|false Путь к файлу, если найден, или false в противном случае
     */
    private function findFileWithExtension($class, $ext) // Приватный метод для поиска файла класса по расширению
    {
        // Поиск по PSR-4
        $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; // Преобразование пространства имён в путь для PSR-4

        $first = $class[0]; // Первая буква префикса
        if (isset($this->prefixLengthsPsr4[$first])) { // Если префиксы для PSR-4 существуют для данной буквы
            $subPath = $class; // Начальный путь — имя класса
            while (false !== $lastPos = strrpos($subPath, '\\')) { // Пытаемся найти последний символ '\\'
                $subPath = substr($subPath, 0, $lastPos); // Обрезаем путь до последнего разделителя
                $search = $subPath . '\\'; // Формируем путь для поиска
                if (isset($this->prefixDirsPsr4[$search])) { // Если такой префикс найден в директориях PSR-4
                    $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); // Окончание пути
                    foreach ($this->prefixDirsPsr4[$search] as $dir) { // Перебираем все директории
                        if (file_exists($file = $dir . $pathEnd)) { // Если файл существует
                            return $file; // Возвращаем путь к файлу
                        }
                    }
                }
            }
        }

        // Поиск в fallback-диках для PSR-4
        foreach ($this->fallbackDirsPsr4 as $dir) {
            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { // Если файл существует в fallback-диках
                return $file;
            }
        }

        // Поиск по PSR-0
        if (false !== $pos = strrpos($class, '\\')) { // Если класс имеет пространство имён
            // Путь для PSR-0 с учётом пространства имён
            $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
                . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
        } else { // Если класс без пространства имён (например, PEAR-like)
            $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; // Преобразуем название класса в путь для PSR-0
        }

        if (isset($this->prefixesPsr0[$first])) { // Если префиксы для PSR-0 существуют для данной буквы
            foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { // Перебираем все префиксы
                if (0 === strpos($class, $prefix)) { // Если класс начинается с данного префикса
                    foreach ($dirs as $dir) { // Перебираем все директории для этого префикса
                        if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { // Если файл существует
                            return $file;
                        }
                    }
                }
            }
        }

        // Поиск в fallback-диках для PSR-0
        foreach ($this->fallbackDirsPsr0 as $dir) {
            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { // Если файл существует в fallback-диках
                return $file;
            }
        }

        // Поиск в путях для включений, если используется include_path.
        if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { // Если используется include_path
            return $file;
        }

        return false; // Если файл не найден, возвращаем false
    }

 

    /**
     * Инициализирует замыкание для включения файлов, если оно ещё не инициализировано.
     *
     * @return void
     */
    private static function initializeIncludeClosure()
    {
        if (self::$includeFile !== null) { // Если замыкание уже инициализировано, выходим из метода
            return;
        }

        /**
         * Изолированное включение.
         *
         * Предотвращает доступ к $this/self из включённых файлов.
         *
         * @param  string $file Путь к файлу для включения
         * @return void
         */
        self::$includeFile = \Closure::bind(static function($file) { // Создаём замыкание для включения файла
            include $file; // Включаем файл
        }, null, null); // Замыкание не привязывается к конкретному объекту или классу
    }
}

 

19 минут чтения Sodium Carbonate

Комментарии (0)

Комментарии отсутствуют
Добавление комментариев доступно только зарегистрированным пользователям

Автор контента

webitproff

Оффлайн

Sodium Carbonate

Последняя авторизация: 20.07.2026 00:04

  • Страница размещена: 30.01.2025 17:56
  • Последнее обновление: 30.01.2025 22:50