thinkphp5.1框架解析(二):自動載入
繼 生命週期的第二篇,大家儘可放心,不會隨便鴿文章的
第一篇中,我們提到了入口指令碼,也說了,裡面註冊了自動載入的功能
- 本文預設你有自動載入和名稱空間的基礎。如果沒有請 看此篇文章 php 類的自動載入與名稱空間
自動載入機制
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的目錄規則重寫了檔案路徑
之後再加我們的目錄檔案
如果沒有找到,就報錯並寫入日誌