1. 程式人生 > >thinkphp5框架實現原理二 自動載入(簡易版)

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);

        }
    }