thinkphp5框架实现原理二 自动加载(简易版)

一、在base.php中 \core\Loader::register();载入自动加载

   /**
     * @param null $autoload
     * 自动加载
     */
    public static function register($autoload = null) {
        // 注册系统自动加载(核心目录Loader的autoload方法)
        spl_autoload_register($autoload ?: '\core\\Loader::autoload', true, true);
        // 注册命名空间定义(注册核心目录命名空间)
        self::addNamespace([
            'core' => ROOT_PATH . 'core' . DS,
        ]);
    }

二、核心目录Loader的autoload方法

    /**
     * 自动加载
     * @access public
     * @param  string $class 类名
     * @return bool
     */
    public static function autoload($class) {
        // 检测命名空间别名
        if (!empty(self::$namespaceAlias)) {
            $namespace = dirname($class);
            if (isset(self::$namespaceAlias[$namespace])) {
                $original = self::$namespaceAlias[$namespace] . '\\' . basename($class);
                if (class_exists($original)) {
                    return class_alias($original, $class, false);
                }
            }
        }
        //查找类文件是否存在
        if ($file = self::findFile($class)) {
            // 非 Win 环境不严格区分大小写
            if (!IS_WIN || pathinfo($file, PATHINFO_FILENAME) == pathinfo(realpath($file), PATHINFO_FILENAME)) {
                //引入文件
                __include_file($file);
                return true;
            }
        }

        return false;
    }

三、查找类文件是否存在

   /**
     * 查找文件
     * @access private
     * @param  string $class 类名
     * @return bool|string
     */
    private static function findFile($class) {

        // 类库映射
        if (!empty(self::$classMap[$class])) {
            return self::$classMap[$class];
        }

        // 查找 PSR-4(将命名空间转换为路径【core\Config转换为core/Config.php】)
        $logicalPathPsr4 = strtr($class, '\\', DS) . EXT;
        $first = $class[0];

        if (isset(self::$prefixLengthsPsr4[$first])) {
            foreach (self::$prefixLengthsPsr4[$first] as $prefix => $length) {
                if (0 === strpos($class, $prefix)) {
                    foreach (self::$prefixDirsPsr4[$prefix] as $dir) {
                        if (is_file($file = $dir . DS . substr($logicalPathPsr4, $length))) {
                            return $file;
                        }
                    }
                }
            }
        }

        // 查找 PSR-4 fallback dirs
        foreach (self::$fallbackDirsPsr4 as $dir) {
            if (is_file($file = $dir . DS . $logicalPathPsr4)) {
                return $file;
            }
        }

        // 查找 PSR-0
        if (false !== $pos = strrpos($class, '\\')) {
            // namespace class name
            $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
                . strtr(substr($logicalPathPsr4, $pos + 1), '_', DS);
        } else {
            // PEAR-like class name
            $logicalPathPsr0 = strtr($class, '_', DS) . EXT;
        }
        if (isset(self::$prefixesPsr0[$first])) {
            foreach (self::$prefixesPsr0[$first] as $prefix => $dirs) {
                if (0 === strpos($class, $prefix)) {
                    foreach ($dirs as $dir) {
                        if (is_file($file = $dir . DS . $logicalPathPsr0)) {
                            return $file;
                        }
                    }
                }
            }
        }
        // 查找 PSR-0 fallback dirs
        foreach (self::$fallbackDirsPsr0 as $dir) {
            if (is_file($file = $dir . DS . $logicalPathPsr0)) {
                return $file;
            }
        }
        // 找不到则设置映射为 false 并返回
        return self::$classMap[$class] = false;
    }

四、引入类文件

/**
 * 引入文件
 * @param  string $file 文件路径
 * @return mixed
 */
function __include_file($file) {
    return include $file;
}

五、加载核心目录命名空间【core】

self::addNamespace([ 'core' => ROOT_PATH . 'core' . DS,]);

    /**
     * 注册命名空间
     * @access public
     * @param  string|array $namespace 命名空间
     * @param  string $path 路径
     * @return void
     */
    public static function addNamespace($namespace, $path = '') {
        if (is_array($namespace)) {
            foreach ($namespace as $prefix => $paths) {
                //添加 PSR-4 空间【core\, __ROOT__/core】
                self::addPsr4($prefix . '\\', rtrim($paths, DS), true);
            }
        } else {
            //添加 PSR-4 空间
            self::addPsr4($namespace . '\\', rtrim($path, DS), true);
        }
    }

添加 PSR-4 空间

/**
     * 添加 PSR-4 空间
     * 把命名空间映射添加到命名空间里【array(1) { ["core\"]=> array(1) { [0]=> "__ROOT__/core" } }】
     * @access private
     * @param  array|string $prefix 空间前缀
     * @param  string $paths 路径
     * @param  bool $prepend 预先设置的优先级更高
     * @return void
     */
    private static function addPsr4($prefix, $paths, $prepend = false) {
        if (!$prefix) {
            // Register directories for the root namespace.
            self::$fallbackDirsPsr4 = $prepend ?
                array_merge((array)$paths, self::$fallbackDirsPsr4) :
                array_merge(self::$fallbackDirsPsr4, (array)$paths);

        } elseif (!isset(self::$prefixDirsPsr4[$prefix])) {
            // Register directories for a new namespace.
            $length = strlen($prefix);
            if ('\\' !== $prefix[$length - 1]) {
                throw new \InvalidArgumentException(
                    "A non-empty PSR-4 prefix must end with a namespace separator."
                );
            }

            self::$prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
            self::$prefixDirsPsr4[$prefix] = (array)$paths;

        } else {
            self::$prefixDirsPsr4[$prefix] = $prepend ?
                // Prepend directories for an already registered namespace.
                array_merge((array)$paths, self::$prefixDirsPsr4[$prefix]) :
                // Append directories for an already registered namespace.
                array_merge(self::$prefixDirsPsr4[$prefix], (array)$paths);

        }
    }

猜你喜欢

转载自blog.csdn.net/sinat_28156831/article/details/80890507
今日推荐