namespace Ice; /** * PSR-4 autoloader class. * * @package Ice/Loader * @category Library * @author Ice Team * @copyright (c) 2014-2023 Ice Team * @license http://iceframework.org/license */ class Loader { protected prefixes = []; /** * Loader constructor. * * @param array prefixes */ public function __construct(array prefixes = []) { if !empty prefixes { var prefix, dir; for prefix, dir in prefixes { this->addNamespace(prefix, dir); } this->register(); } } /** * Register loader with SPL autoloader stack. * * @return void */ public function register() { spl_autoload_register([this, "loadClass"]); } /** * Adds a base directory for a namespace prefix. * * @param string prefix The namespace prefix * @param string baseDir A base directory for class files in the namespace * @param bool prepend If true, prepend the base directory to the stack instead of appending it; this causes it to * be searched first rather than last * @return Loader */ public function addNamespace(string prefix, string baseDir = null, boolean prepend = false) { // normalize namespace prefix let prefix = trim(prefix, "\\") . "\\"; // normalize the base directory with a trailing separator let baseDir = rtrim(baseDir, "/") . DIRECTORY_SEPARATOR, baseDir = rtrim(baseDir, DIRECTORY_SEPARATOR) . "/"; // initialize the namespace prefix array if !isset this->prefixes[prefix] { // Refcount of the new array zephir/issues/1140 let this->prefixes[prefix] = [baseDir]; return this; } // retain the base directory for the namespace prefix if prepend { array_unshift(this->prefixes[prefix], baseDir); } else { array_push(this->prefixes[prefix], baseDir); } return this; } /** * Loads the class file for a given class name. * * @param string className The fully-qualified class name * @return mixed The mapped file name on success, or boolean false on failure */ public function loadClass(string className) { var prefix, pos, relativeClass, mappedFile; // the current namespace prefix let prefix = className; // work backwards through the namespace names of the fully-qualified // class name to find a mapped file name let pos = strrpos(prefix, "\\"); if pos === false { // try to load a mapped file for the prefix and relative class let mappedFile = this->loadMappedFile("\\", className); if mappedFile { return mappedFile; } } else { do { // retain the trailing namespace separator in the prefix let prefix = substr(className, 0, pos + 1); // the rest is the relative class name let relativeClass = substr(className, pos + 1); // try to load a mapped file for the prefix and relative class let mappedFile = this->loadMappedFile(prefix, relativeClass); if mappedFile { return mappedFile; } // remove the trailing namespace separator for the next iteration // of strrpos() let prefix = rtrim(prefix, "\\"); let pos = strrpos(prefix, "\\"); } while pos !== false; } // never found a mapped file return false; } /** * Load the mapped file for a namespace prefix and relative class. * * @param string $prefix The namespace prefix * @param string $relative_class The relative class name * @return mixed Boolean false if no mapped file can be loaded, or the name of the mapped file that was loaded */ protected function loadMappedFile(string prefix, string relativeClass) { var baseDir, file; // are there any base directories for this namespace prefix? if !isset this->prefixes[prefix] { return false; } let relativeClass = str_replace("\\", DIRECTORY_SEPARATOR, relativeClass) . ".php"; // look through base directories for this namespace prefix for baseDir in this->prefixes[prefix] { // replace the namespace prefix with the base directory, // replace namespace separators with directory separators // in the relative class name, append with .php let file = baseDir . relativeClass; // if the mapped file exists, require it if this->requireFile(file) { // yes, we"re done return file; } } // never found it return false; } /** * If a file exists, require it from the file system. * * @param string $file The file to require * @return bool True if the file exists, false if not */ protected function requireFile(string file) { if file_exists(file) { require file; return true; } return false; } }