Thinkphp5.1類自動加載機制

tp5.1類加載功能都封裝到Loader類當中,所以我們主要分析這個類的主要功能。

1.幾個重要屬性

Loader::$prefixLengthsPsr4, 

Loader::$prefixDirsPsr4,

Loader:: $fallbackDirsPsr4,

Loader::$classMap

2.自動加載流程

2.1自動加載整個流程是通過Loader::register來實現的。

2.1.1.首先註冊系統自動加載函數

所以自動加載函數就是Loader::autoload(), 註冊後,當後面的代碼有實例化不存在的類時,會直接調動這個方法。

2.1.2.然後 Composer自動加載支持

require composer目錄(\vendor\composer\)下的autoload_static.php文件,把autoload_static.php類的$prefixLengthsPsr4,$prefixDirsPsr4兩個屬性值賦值給Loader::$prefixLengthsPsr4, Loader::$prefixDirsPsr4屬性。

當我們通過composer方式下載插件到項目的時候,composer命令會修改autoload_static.php中的$prefixLengthsPsr4,$prefixDirsPsr4這兩個屬性,指定該擴展的命名空間和對應目錄。所以如果我們直接複製擴展到verdon目錄的時候,需要修改這兩個屬性值,不然框架加載不到這個擴展。但是建議用composer命令來下載擴展,讓命令自動幫我們修改。

這時Loader::$prefixLengthsPsr4, Loader::$prefixDirsPsr4就包含了composer下面的命名空間和對應的目錄了。

 2.1.3.命名空間think,traits加載支持

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

這段代碼的意思就是在Loader::$prefixLengthsPsr4, Loader::$prefixDirsPsr4寫入think, traits命名空間對應的目錄。

2.1.4. 加載類庫映射文件

// 加載類庫映射文件
 if (is_file($rootPath . 'runtime' . DIRECTORY_SEPARATOR . 'classmap.php')) {
    self::addClassMap(__include_file($rootPath . 'runtime' . DIRECTORY_SEPARATOR . 'classmap.php'));
}

這段代碼判斷runtime\classmap.php文件是否存在,如果存在就把數據寫入Loader::$classMap,這個其實就是用文件緩存類與類文件的映射關係。後面我們會講到,代碼實例化不存在的類時,會先include類文件,找類文件其實就是通過Loader的這幾個屬性來找的,如果存在$classMap,就直接找到類文件,提高了效率。

2.1.5.自動加載extend目錄

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

這段代碼就是把extend目錄路徑寫入到屬性Loader:: $fallbackDirsPsr4

通過執行Loader::register()方法,可以確定vender目錄(通過composer下載的擴展目錄),框架核心think,trait目錄,extend目錄對應的命名空間,文件路徑信息已經裝載到Loader::$prefixLengthsPsr4, Loader::$prefixDirsPsr4,Loader:: $fallbackDirsPsr4,Loader::$classMap這幾個屬性中。後面自動加載函數Loader::autoload($class),就是通過這幾個屬性找到對應的類文件,加載進來。

 2.2自動加載函數Loader::autoload();

先通過self::$classAlias屬性確定類和目錄的映射,php的系統函數class_alias可以把類加載進來,並且可以使用別名來new這個類。正常情況我們通過Loader::findFile()找到類文件路徑,然後include進來。

2.2.1Loader::findFile()過程,通過類找到對應的類文件路徑

這個過程,就是通過Loader::$prefixLengthsPsr4, Loader::$prefixDirsPsr4,Loader:: $fallbackDirsPsr4,Loader::$classMap這幾個屬性中確定類文件路徑。理解了這幾個屬性的格式,也就理解系統如何加載類文件了。

Loader::$classMap這個屬性值是通過文件緩存獲取類文件路徑的,在根目錄使用命令 php think optimize:autoload,會在runtime目錄生成classmap.php文件。

Loader::$prefixLengthsPsr4的打印結果:

array(2) {
//命名空間第一個字母爲key
  ["t"]=>  array(3) {
    //命名空間爲key, 命名空間字符長度爲value
    ["think\composer\"]=> int(15)
    ["think\"]=> int(6)
    ["traits\"]=>int(7)
  }
  ["a"]=>  array(1) {
    ["app\"]=>int(4)
  }
}

 Loader::$prefixDirsPsr4的打印結果:

array(4) {
//命名空間key,綁定的目錄爲value
  ["think\composer\"]=>  array(1) {
    [0]=>string(69) "C:\xampp\htdocs\tp5.1\vendor\composer/../topthink/think-installer/src"
  }
  ["app\"]=>  array(1) {
    [0]=>string(55) "C:\xampp\htdocs\tp5.1\vendor\composer/../../application"
  }
  ["think\"]=>  array(1) {
    [0]=>string(44) "C:\xampp\htdocs\tp5.1\thinkphp\library\think"
  }
  ["traits\"]=>  array(1) {
    [0]=> string(45) "C:\xampp\htdocs\tp5.1\thinkphp\library\traits"
  }
}

 Loader:: $fallbackDirsPsr4打印結果

array(1) {
  [0]=>string(28) "C:\xampp\htdocs\tp5.1\extend"
}

findFile過程中,確定類文件路徑是通過目錄+類.php拼接而成的。比如實例化\think\Error,拼接到的文件路徑爲"C:\xampp\htdocs\tp5.1\thinkphp\library\think\Error.php"。僞代碼如下:

//$class就是\think\Error
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . '.php';

//通過屬性$prefixDirsPsr4查找到文件
$file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length);

//通過屬性$fallbackDirsPsr4查找到文件
$file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4

//通過屬性$classmap查找文件
$file = $classmap[$class];

2.3添加命名空間

// 註冊應用命名空間
Loader::addNamespace($this->namespace, $this->appPath);主動添加命名空間和對應的目錄地址。

其實是把相關信息寫入Loader::$prefixLengthsPsr4, Loader::$prefixDirsPsr4這兩個屬性。 

比如application目錄的命名空間爲app, 在框架啓動的應用初始化時initialize(),會註冊app命名空間和目錄,這樣使用application目錄的類的時候,自動加載函數才能找到類文件。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章