摘要:源碼分析自動加載系統會調用方法注冊自動加載,在這一步完成后,所有符合規范的類庫包括依賴加載的第三方類庫都將自動加載。是通過加載對應的文件進行注冊加載的。
源碼分析 自動加載
系統會調用 Loader::register()方法注冊自動加載,在這一步完成后,所有符合規范的類庫(包括Composer依賴加載的第三方類庫)都將自動加載。
系統的自動加載由下面主要部分組成:
1. 注冊系統的自動加載方法 hinkLoader::autoload 2. 注冊系統命名空間定義 3. 加載類庫映射文件(如果存在) 4. 如果存在Composer安裝,則注冊**Composer**自動加載 5. 注冊extend擴展目錄
一個類庫的自動加載檢測順序為:
1. 是否定義類庫映射; 2. PSR-4自動加載檢測; 3. PSR-0自動加載檢測; 4. 可以看到,定義類庫映射的方式是最高效的。源碼
/** * 注冊自動加載機制 * @access public * @param callable $autoload 自動加載處理方法 * @return void */ public static function register($autoload = null) { // 注冊系統自動加載 spl_autoload_register($autoload ?: "thinkLoader::autoload", true, true); // Composer 自動加載支持 if (is_dir(VENDOR_PATH . "composer")) { if (PHP_VERSION_ID >= 50600 && is_file(VENDOR_PATH . "composer" . DS . "autoload_static.php")) { require VENDOR_PATH . "composer" . DS . "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::addNamespace([ "think" => LIB_PATH . "think" . DS, "behavior" => LIB_PATH . "behavior" . DS, "traits" => LIB_PATH . "traits" . DS, ]); // 加載類庫映射文件 if (is_file(RUNTIME_PATH . "classmap" . EXT)) { self::addClassMap(__include_file(RUNTIME_PATH . "classmap" . EXT)); } self::loadComposerAutoloadFiles(); // 自動加載 extend 目錄 self::$fallbackDirsPsr4[] = rtrim(EXTEND_PATH, DS); }框架自動加載
/** * 自動加載 * @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; }檢測命名空間別名
檢查是否添加了命名空間別名,通過別名尋找原命名空間。如:
//原 AppHttpControllerIndex::class //添加別名后 ControllerIndex::class
thinkphp通過 thinkLoader::addNamespaceAlias($namespace, $original) 添加命名空間別名。
//位置在thinkphp/library/think/Loader.php的260行 /** * 注冊命名空間別名 * @access public * @param array|string $namespace 命名空間 * @param string $original 源文件 * @return void */ public static function addNamespaceAlias($namespace, $original = "") { if (is_array($namespace)) { self::$namespaceAlias = array_merge(self::$namespaceAlias, $namespace); } else { self::$namespaceAlias[$namespace] = $original; } }
通過鍵為別名,值為原命名空間的數組,注冊到thinkLoader::$namespaceAlias的屬性。
通過classmap,psr-4,psr-0查找文件/** * 查找文件 * @access private * @param string $class 類名 * @return bool|string */ private static function findFile($class) { // 類庫映射 if (!empty(self::$classMap[$class])) { return self::$classMap[$class]; } // 查找 PSR-4 $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; }
thinkphp添加的自動加載是通過psr-4和classmap進行加載,方法分別是: thinkLoader::addClassMap($class, $map = "") 和 thinkLoader::addNamespace($namespace, $path = "")。
psr-4的加載方式是通過命名空間的首字母,查找對應的命名空間,再通過對應的命名空間拼接對應的文件目錄,判斷該文件是否存在,如果存在就加載文件,實現類的自動加載。
classmap的加載方式是通過composer du生成對應的類映射,通過直接查找class對應的文件,從而實現自動加載。
其他的加載方式需要深入了解的可以自行研究代碼。
/** * 注冊自動加載機制 * @access public * @param callable $autoload 自動加載處理方法 * @return void */ public static function register($autoload = null) { .... // 注冊命名空間定義 self::addNamespace([ "think" => LIB_PATH . "think" . DS, "behavior" => LIB_PATH . "behavior" . DS, "traits" => LIB_PATH . "traits" . DS, ]); // 加載類庫映射文件 if (is_file(RUNTIME_PATH . "classmap" . EXT)) { self::addClassMap(__include_file(RUNTIME_PATH . "classmap" . EXT)); } .... }composer自動加載
thinkphp中的composer自動加載不是通過composer自帶的autoload.php進行自動加載的。是通過加載對應的psr文件進行注冊加載的。
/** * 注冊自動加載機制 * @access public * @param callable $autoload 自動加載處理方法 * @return void */ public static function register($autoload = null) { .... // Composer 自動加載支持 if (is_dir(VENDOR_PATH . "composer")) { if (PHP_VERSION_ID >= 50600 && is_file(VENDOR_PATH . "composer" . DS . "autoload_static.php")) { require VENDOR_PATH . "composer" . DS . "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(); } } .... }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/30152.html
摘要:源碼分析入口篇源碼分析應用入口用戶發起的請求都會經過應用的入口文件,通常是文件。當然,你也可以更改或者增加新的入口文件。通常,我們不建議在應用入口文件中加入過多的代碼,尤其是和業務邏輯相關的代碼。 源碼分析---入口篇 源碼分析 應用入口 用戶發起的請求都會經過應用的入口文件,通常是 ==public/index.php==文件。當然,你也可以更改或者增加新的入口文件。 通常入口文件的...
摘要:源碼分析開門篇生命周期入口文件用戶發起的請求都會經過應用的入口文件,通常是文件。注冊錯誤和異常機制執行注冊錯誤和異常處理機制。由三部分組成應用關閉方法錯誤處理方法異常處理方法注冊應用關閉方法是為了便于攔截一些系統錯誤。 源碼分析—開門篇 thinkphp生命周期 1、入口文件 用戶發起的請求都會經過應用的入口文件,通常是 ==public/index.php==文件。當然,你也可以更改...
摘要:如果遍歷后沒有找到,則加載失敗。在之后碰到了之后直接拿來用,提高系統自動加載的性能。這里我們就講完了注冊自動加載。使用自動加載我們在中定義了我們自動加載函數式方法。 繼 生命周期的第二篇,大家盡可放心,不會隨便鴿文章的 第一篇中,我們提到了入口腳本,也說了,里面注冊了自動加載的功能 本文默認你有自動加載和命名空間的基礎。如果沒有請 看此篇文章 php 類的自動加載與命名空間 自動加載...
摘要:索性讀一下它的源碼。行載入類載入類,這個類比較重要,實現了自動加載。注冊錯誤和異常處理機制加載慣例配置文件接下來我們看一下自動加載的實現方法。所以借助此函數可以達到自動加載。博客鏈接解讀源碼一自動加載 聽說 TP5 已經 RC4 了,曾經在 RC3 的時候用它寫過一個小東西。官方說從 RC4 以后改動不是太大。索性讀一下它的源碼。然后順便記錄一下,如有錯漏,請路過大神多多指正! 入口 ...
摘要:對于這兩種不同形式的參數,處理方式也不一樣,為字符串形式字符串則表示單個配置設置二維數組判斷字符串中是否帶沒有直接把的小寫形式作為,作為值設置到配置中如果帶,只處理前面兩項,即把字符串通過分割成數組,取數組的前面兩項,把設置到配置中。 源碼分析---入口篇 源碼分析 全局配置加載類 全局配置類的主要代碼如下: class Config { /** * @var ar...
閱讀 1563·2023-04-25 15:50
閱讀 1304·2021-09-22 15:49
閱讀 2931·2021-09-22 15:06
閱讀 3569·2019-08-30 15:54
閱讀 2331·2019-08-29 11:33
閱讀 2118·2019-08-23 17:56
閱讀 2144·2019-08-23 17:06
閱讀 1293·2019-08-23 15:55