由於受到疫情影響,小智典營銷,線下課預售暫停一段時間,本來推薦使用微信直播的功能,但由於領導層強烈推薦使用第三方工具小鵝通,導致專案暫緩,僅僅對於線上業務進行開發維護。那就趁有時間學習一下新知識。然而學習什麼新知識不重要,最重要的就是不要不學習。我也很迷茫,不知道先學什麼,總是,這也想學,那也想學,然而到最後還是在原地踏步,痛定思痛,我先定一個計劃,說學什麼就規定在一段時間內就學這個,其他的先不管。學完一個再說。之前面試的時候,經常有人問,有研究過某個框架的原始碼沒。那就先從研究框架的原始碼吧。由於最近的專案是用TP5.1.39開發的,那就研究tp5.1吧。
TP5.1中類的自動載入機制
首先進入專案入口檔案
前提是你安裝了tp5.1.39
,composer create-project topthink/think=5.1.* tp5
public\index.php
//1、定義名稱空間
namespace think;
//2、包含並執行base.php檔案
require __DIR__ . '/../thinkphp/base.php';
//3、執行應用並響應
Container::get('app')->run()->send();
進入base.php檔案,看看都做了哪些操作
1、引入Loader
類,需要注意的是,僅僅是引入類,並沒有執行什麼。
2、執行Loader::register()
方法,註冊自動載入機制
我們進入該方法,首先利用
spl_autoload_register
註冊系統自動載入機制,含義是:系統在new一個物件的時候,發現類不存在時,就是呼叫Loader::autoload
的靜態方法去引入載入對應的類然後獲取專案的根目錄,設定專案的composer的目錄,引入
autoload_static.php
檔案,然後獲取已經宣告的類檔案,並彈出最後一個類名,此類名就是autoload_static.php
檔案中宣告的類,並將此類的屬性賦值給Loader類的屬性,可以把此步驟理解為註冊app
,think\composer
名稱空間以及對應的目錄然後再註冊
think
,traits
名稱空間以及對應的目錄然後註冊類名對映,
runtime/classmap.php
,此類檔案是由後期優化生成的,php think optimize:autoload
然後註冊自動載入目錄
extend
3、然後執行Error::register()
方法
由於
think\Error
類並沒有事先引入,所以系統呼叫上一步註冊的系統自動載入機制,執行Loader::autoload
方法,此時引數為think\Error
,進入autoload
方法,首先檢視類庫別名中是否有此類名,如果有的話,就使用class_alias
函式起別名,並自動載入。如果不存在類庫,那就根據類名去查詢檔案,也就是執行findFile
方法,首先檢視是否存在類庫對映(classMap),如果存在就返回檔案目錄地址,不存在的話,就查詢psr-4並返回檔案目錄地址,如果找不到就繼續查詢psr-4自動載入目錄,如果再找不到就查詢psr-0規範的檔案目錄,如果再差找不到,就查詢psr-0自動載入目錄,返回檔案目錄地址,最後引入該檔案然後執行
register
方法,註冊異常處理
4、註冊類庫別名,Loader::addClassAlias
,方便autoload
Loader::addClassAlias([
'App' => facade\App::class, // 對應的類檔案目錄 => thinkphp\library\think\facade\App.php
'Build' => facade\Build::class,
'Cache' => facade\Cache::class,
'Config' => facade\Config::class,
'Cookie' => facade\Cookie::class,
'Db' => Db::class,
'Debug' => facade\Debug::class,
'Env' => facade\Env::class,
'Facade' => Facade::class,
'Hook' => facade\Hook::class,
'Lang' => facade\Lang::class,
'Log' => facade\Log::class,
'Request' => facade\Request::class,
'Response' => facade\Response::class,
'Route' => facade\Route::class,
'Session' => facade\Session::class,
'Url' => facade\Url::class,
'Validate' => facade\Validate::class,
'View' => facade\View::class,
]);
擴充套件
1、由於autoload_static.php
檔案中的類名一直在變化,我們無法得到固定的類名,怎麼做才能將此類的屬性與Loader的屬性合併?
//主要使用兩個函式 get_declared_classes property_exists
//獲取類名
$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};
}
}
2、為什麼使用名稱空間對映?
節省資源,方便呼叫,避免每次迴圈查詢
3、PSR4 標準頂級名稱空間對映陣列,用了兩個陣列,第一個是用名稱空間第一個字母作為字首索引,然後是 頂級名稱空間,但是最終並不是檔案路徑,而是 頂級名稱空間的長度。為什麼呢?
因為 PSR4 標準是用頂級名稱空間目錄替換頂級名稱空間,所以獲得頂級名稱空間的長度很重要,與Loader::findFile
方法中字串擷取拼接類檔案所在位置有用到length
4、如果需要增加一個新的名稱空間,或者新增一個自動載入目錄,你會怎麼做?
主要是使用方法Load::addNamespace
和Loader::addAutoLoadDir
,在Loader
內部外部都可以,但為了不修改原始碼,建議在入口檔案呼叫新增
5、類庫別名class_alias
eg.直接使用Config
類的話,自動載入機制會直接呼叫Loader::$classAlias
屬性中對應鍵名的鍵值類庫
namespace app\index\controller;
use Config;//此時的Config類,在編輯器中滑鼠點選是跳轉不了的
class Index
{
public function index()
{
$appConfig = Config::get('app.');
var_dump($appConfig);
}
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結