1. 程式人生 > >thinkphp5.1框架解析(二):自動載入

thinkphp5.1框架解析(二):自動載入

繼 生命週期的第二篇,大家儘可放心,不會隨便鴿文章的

第一篇中,我們提到了入口指令碼,也說了,裡面註冊了自動載入的功能

自動載入機制

php 的自動載入是Loader 類中實現的,這個類在 base.php 中被引入

//base .php
// 載入Loader類
require __DIR__ . '/library/think/Loader.php';

// 註冊自動載入
Loader::register();

我們程式在這裡執行了 Loader 中靜態方法 ,同時這也是一個全部的類register()

我們進入 Loader.php ,按照上面執行順序看看其核心是什麼?
此方法行數過長,我們一點一點來分析

// 註冊系統自動載入
        spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true);

這就是註冊我們的自動載入函式,$autoload 這個變數是傳的引數,然而我查詢 tp5.1 原始碼,也沒有發現有任何傳參的動作。我認為是多餘的引數,直接寫'think\\Loader::autoload' 就可以了。

如果不瞭解這個函式的同學,請看文章最頂部的那個連線,上面有詳細講解。

$rootPath
= self::getRootPath(); self::$composerPath = $rootPath . 'vendor' . DIRECTORY_SEPARATOR . 'composer' . DIRECTORY_SEPARATOR; // Composer自動載入支援 if (is_dir(self::$composerPath)) { if (is_file(self::$composerPath . 'autoload_static.php')) { require self
::$composerPath . 'autoload_static.php'; $declaredClass = get_declared_classes(); $composerClass = array_pop($declaredClass); foreach (['prefixLengthsPsr4', 'prefixDirsPsr4', 'fallbackDirsPsr4', 'prefixesPsr0', 'fallbackDirsPsr0', 'classMap', 'files'] as $attr) { if (property_exists($composerClass, $attr)) { self::${$attr} = $composerClass::${$attr}; } } } else { self::registerComposerLoader(self::$composerPath); } }

為了支援 composer 拓展,在自動註冊時候,把composer 也順帶一起註冊了,把composer 目錄對映關係存放到 prefixDirsPsr4這個靜態變數中,方便對拓展的呼叫。

// 註冊名稱空間定義
        self::addNamespace([
            'think'  => __DIR__,
            'traits' => dirname(__DIR__) . DIRECTORY_SEPARATOR . 'traits',
        ]);

        // 載入類庫對映檔案
        if (is_file($rootPath . 'runtime' . DIRECTORY_SEPARATOR . 'classmap.php')) {
            self::addClassMap(__include_file($rootPath . 'runtime' . DIRECTORY_SEPARATOR . 'classmap.php'));
        }

        // 自動載入extend目錄
        self::addAutoLoadDir($rootPath . 'extend');

這後面的程式碼都大同小異,都是把 所需要用到的類,對映到prefixDirsPsr4這個靜態變數中。到時候方便我們使用名稱空間進行呼叫。

register() 函式這裡就大概分析結束了。 接下來我們講一講autoload()

自動載入

上面我們講spl_autoload_register的時候,說他註冊了 autoload()函式,使我們在找不到類的情況下,來呼叫此函式。

//函式整體內容
public static function autoload($class)
    {
        if (isset(self::$classAlias[$class])) {
            return class_alias(self::$classAlias[$class], $class);
        }

        if ($file = self::findFile($class)) {

            // Win環境嚴格區分大小寫
            if (strpos(PHP_OS, 'WIN') !== false && pathinfo($file, PATHINFO_FILENAME) != pathinfo(realpath($file), PATHINFO_FILENAME)) {
                return false;
            }

            __include_file($file);
            return true;
        }
    }

我們擷取片段一點一點分析。

if (isset(self::$classAlias[$class])) {
            return class_alias(self::$classAlias[$class], $class);
        }

這一段是判斷我們是否是使用了 TP5.1的 靜態呼叫介面(Facade) ,具體解釋可以參照官方文件的解釋,這個是在 base.php的末尾註冊的

if ($file = self::findFile($class)) {

            // Win環境嚴格區分大小寫
            if (strpos(PHP_OS, 'WIN') !== false && pathinfo($file, PATHINFO_FILENAME) != pathinfo(realpath($file), PATHINFO_FILENAME)) {
                return false;
            }

            __include_file($file);
            return true;
        }

findFile($class) 主要功能是根據類的名稱,配合我們之前儲存對映關係的靜態陣列prefixDirsPsr4來找尋檔案的目錄。

如果找到就消除 linux 和 window 對路徑名稱的差異。(linux 嚴格區分大小寫,而win 沒有嚴格區分)

這裡主要是擔心在window環境下,路徑名稱大小寫沒分,所以我們根據linux的目錄規則重寫了檔案路徑

之後再加我們的目錄檔案

如果沒有找到,就報錯並寫入日誌