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 minutes read Sodium Carbonate

Comments (0)

No comments yet
Only registered users can post new comments

Content author

webitproff

Offline

Sodium Carbonate

Last logged: 2026-09-03 18:32

About me briefly
Support and development of web projects on the CMF Cotonti: private messengers via the website, open and closed small social networks, trading platforms and marketplaces, freelance and services exchange portal, catalogs of goods from wholesale suppliers, dropshipping platforms, online stores, and much more.
View developments and download
Public portfolio of my works and developments
Telegram for messages
@webitproff
Telegram channel
@s/aBuyFILE
  • Page published: 2025-01-30 17:56
  • Last update: 2025-01-30 22:50