国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

ThinkPHP5.1 源碼淺析(二)自動加載機制

mudiyouyou / 620人閱讀

摘要:如果遍歷后沒有找到,則加載失敗。在之后碰到了之后直接拿來用,提高系統自動加載的性能。這里我們就講完了注冊自動加載。使用自動加載我們在中定義了我們自動加載函數式方法。

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

第一篇中,我們提到了入口腳本,也說了,里面注冊了自動加載的功能

本文默認你有自動加載和命名空間的基礎。如果沒有請 看此篇文章 php 類的自動加載與命名空間

自動加載機制

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

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

// 注冊自動加載
Loader::register();

我們程序在這里執行了 Loader 中靜態方法 ,同時這也是一個全部的類register() 我們進入 Loader.php ,按照上面執行順序看看其核心是什么?

register()方法執行流程

注冊系統自動加載

此方法行數過長,我們一點一點來分析

// 注冊系統自動加載
        spl_autoload_register($autoload ?: "thinkLoader::autoload", true, true);

這就是注冊我們的自動加載函數,$autoload 這個變量是傳的參數,考慮到你可以自己實現自己的加載類,為了方便拓展,TP可以讓你自己實現自己的類加載方法。

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

Composer自動加載支持
$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 也順帶一起注冊了,方便對拓展的調用。

autoload_static.php中的變量加載進內存中有一個難題:由于autoload_static.php 文件中的類名一直在變化,我們無法得到固定的類名。(如我系統中 類名為 ComposerStaticInit5109814b18095308ffe89ba7a1be18df

為了把 require self::$composerPath . "autoload_static.php"; 中 的屬性 載入進程序中,在這里我們換了一種形式

首先,獲取程序中加載的所有類名,然后取我們最后一個加載的類名(即數組中的最后一個)。

$declaredClass = get_declared_classes(); 
$composerClass = array_pop($declaredClass);

拿到了我們的類名,調用 property_exists($composerClass, $attr)檢查類中是否存在指定的屬性

疑問: composer_static 的參數代表是什么?
 foreach (["prefixLengthsPsr4", "prefixDirsPsr4", "fallbackDirsPsr4", "prefixesPsr0", "fallbackDirsPsr0", "classMap", "files"] as $attr)  中后面 ("fallbackDirsPsr4", "prefixesPsr0", "fallbackDirsPsr0", "classMap", "files")的作用是什么?
classMap(命名空間映射)
  public static $classMap = array (

      "AppHttpControllersAuthForgotPasswordController"
              => __DIR__ . "/../.." . "/app/Http/Controllers/Auth/ForgotPasswordController.php",

      "AppHttpControllersAuthLoginController"
              => __DIR__ . "/../.." . "/app/Http/Controllers/Auth/LoginController.php",

      "AppHttpControllersAuthRegisterController"
              => __DIR__ . "/../.." ,
              ……
)

直接命名空間全名與目錄的映射,簡單粗暴,也導致這個數組相當的大。

PSR4 標準頂級命名空間映射數組:
  public static $prefixLengthsPsr4 = array(
      "p" => array (
        "phpDocumentorReflection" => 25,
    ),
      "S" => array (
        "SymfonyPolyfillMbstring" => 26,
        "SymfonyComponentYaml" => 23,
        "SymfonyComponentVarDumper" => 28,
        ...
    ),
  ...);

  public static $prefixDirsPsr4 = array (
      "phpDocumentorReflection" => array (
        0 => __DIR__ . "/.." . "/phpdocumentor/reflection-common/src",
        1 => __DIR__ . "/.." . "/phpdocumentor/type-resolver/src",
        2 => __DIR__ . "/.." . "/phpdocumentor/reflection-docblock/src",
    ),
       "SymfonyPolyfillMbstring" => array (
        0 => __DIR__ . "/.." . "/symfony/polyfill-mbstring",
    ),
      "SymfonyComponentYaml" => array (
        0 => __DIR__ . "/.." . "/symfony/yaml",
    ),
  ...)

PSR4 標準頂級命名空間映射用了兩個數組,第一個是用命名空間第一個字母作為前綴索引,然后是 頂級命名空間,但是最終并不是文件路徑,而是 頂級命名空間的長度。為什么呢?

因為 PSR4 標準是用頂級命名空間目錄替換頂級命名空間,所以獲得頂級命名空間的長度很重要。

具體說明這些數組的作用:

假如我們找 SymfonyPolyfillMbstringexample 這個命名空間,通過前綴索引和字符串匹配我們得到了

"SymfonyPolyfillMbstring" => 26,

這條記錄,鍵是頂級命名空間,值是命名空間的長度。拿到頂級命名空間后去 $prefixDirsPsr4數組 獲取它的映射目錄數組:(注意映射目錄可能不止一條)

 array (
              0 => __DIR__ . "/.." . "/symfony/polyfill-mbstring",
          )

然后我們就可以將命名空間 SymfonyPolyfillMbstringexample 前26個字符替換成目錄 __DIR__ . "/.." . "/symfony/polyfill-mbstring ,我們就得到了__DIR__ . "/.." . "/symfony/polyfill-mbstring/example.php,先驗證磁盤上這個文件是否存在,如果不存在接著遍歷。如果遍歷后沒有找到,則加載失敗。

注: 其實作為一個web框架,composer里面的東西,不應該由ThinkPHP關心的,但由于 TP5 自己原生的框架包 的設計沒有完全包容 composer, 所在注冊自動加載的時候會拿去其屬性值自己來使用(僅限自己理解,如果與您觀點不同歡迎討論)

注冊命名空間定義
// 注冊命名空間定義
        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");

這后面的代碼都大同小異,都是把 所需要用到的類,映射到Psr4空間這個靜態變量中。到時候方便我們使用命名空間進行調用。

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

在 TP5 代碼下執行php think optimize:autoload 就會在runtime下生成 classmap.php 文件,文件形式

return [
    "appindexcontrollerIndex" => "D:/app/tp5/application/" . "index/controller/Index.php",
    "thinkApp" => "D:/app/tp5/thinkphp/library/" . "/think/App.php",
    "thinkBuild" => "D:/app/tp5/thinkphp/library/" . "/think/Build.php",
    "thinkCache" => "D:/app/tp5/thinkphp/library/" . "/think/Cache.php",
    "thinkCollection" => "D:/app/tp5/thinkphp/library/" . "/think/Collection.php",
    ...
    ]

生成類庫映射文件,會在runtime目錄下面生成classmap.php文件,生成的類庫映射文件會掃描系統目錄和應用目錄的類庫。在之后碰到了之后直接拿來用,提高系統自動加載的性能。

register() 函數這里就大概分析結束了。 這里我們就講完了 注冊自動加載。

使用自動加載

我們在 register 中定義了我們自動加載函數式 Loader::autoload()方法。 我們就小試牛刀,在我們的 base.php 中,我們加載完 自動加載機制后,就會加載我們的異常處理

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

// 注冊自動加載
Loader::register();

// 注冊錯誤和異常處理機制
Error::register();

在這時的狀態里 Error 不存在,所有會進入我們的自動加載方法中重新試一下。

//函數整體內容
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);
        }

這一段是判斷我們我們是否對該類設置別名,但明顯我們此時還沒有設置。

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) 如果我們之前緩存了 classMap 在runtime文件夾下,那么他會直接返回。(這也就是為什么我們緩存 classMap 會提升性能的原因),如果沒有緩存就配合我們之前存儲映射關系的靜態數組prefixDirsPsr4,和 prefixLengthsPsr4來找尋文件的目錄,速度會相對慢很多。 如果沒有找到那么就返回空, spl_autoload_register 會判斷沒有找到該類,拋出錯誤。

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

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

之后再加我們的目錄文件

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/31572.html

相關文章

  • Java相關

    摘要:本文是作者自己對中線程的狀態線程間協作相關使用的理解與總結,不對之處,望指出,共勉。當中的的數目而不是已占用的位置數大于集合番一文通版集合番一文通版垃圾回收機制講得很透徹,深入淺出。 一小時搞明白自定義注解 Annotation(注解)就是 Java 提供了一種元程序中的元素關聯任何信息和著任何元數據(metadata)的途徑和方法。Annotion(注解) 是一個接口,程序可以通過...

    wangtdgoodluck 評論0 收藏0
  • 微信小程序的require機制淺析

    摘要:注意,這就與普通的腳本引用加載立即執行完全不同了接下來,就輪到微信小程序的函數出場了。所以深入理解微信小程序的模塊化機制也是很有價值的 (注: 本文中所列微信小程序工具代碼,并非為微信小程序原始代碼,而是學習歸納的示意代碼) 在學習開發微信小程序中, 分析總結了最近版本微信小程序模塊化的函數 require的加載與初始化模塊機制,歸納說來,小程序JS模塊加載可分為兩大步驟:一,JS模塊...

    boredream 評論0 收藏0
  • 淺析webpack源碼之convert-argv模塊(

    摘要:接下來我看看一下函數我們先按照分支走為讀取是里的對象,饒了這大的一個圈子,那么接下來一起來看一看對你的輸入配置做了怎么樣的處理吧 打開webpeck-cli下的convert-argv.js文件 // 定義options為空數組 const options = []; // webpack -d 檢查 -d指令 if (argv.d) { //... } ...

    lemon 評論0 收藏0
  • webkit渲染機制淺析

    摘要:模塊和將下面的渲染機制,安全機制,插件機制等等隱藏起來,提供一個接口層。進行網頁的渲染進程,可能有多個。最后進程將結果由線程傳遞給進程最后,進程接收到結果并將結果繪制出來。 這是之前在簡書上面的處女作,也搬過來了,以后就一直在 segmentfault 上面寫文章了,webkit技術內幕-朱永盛是我大四買的書,很舊的一本書了,當時只看了一點點,一直沒繼續看完它,現在才看完,,,說來慚愧...

    Cobub 評論0 收藏0
  • 【騰訊Bugly干貨分享】Android ListView與RecyclerView對比淺析--緩存

    摘要:數據源頻繁更新的場景,如彈幕等的優勢會非常明顯進一步來講,結論是列表頁展示界面,需要支持動畫,或者頻繁更新,局部刷新,建議使用,更加強大完善,易擴展其它情況如微信卡包列表頁兩者都,但在使用上會更加方便,快捷。 本文來自于騰訊bugly開發者社區,非經作者同意,請勿轉載,原文地址:http://dev.qq.com/topic/5811d... 作者:黃寧源 一,背景 RecyclerV...

    wangzy2019 評論0 收藏0

發表評論

0條評論

mudiyouyou

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<