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

資訊專欄INFORMATION COLUMN

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

mudiyouyou / 609人閱讀

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

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

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

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

自動加載機制

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

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

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

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

register()方法執(zhí)行流程

注冊系統(tǒng)自動加載

此方法行數(shù)過長,我們一點一點來分析

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

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

如果不了解這個函數(shù)的同學(xué),請看文章最頂部的那個連接,上面有詳細(xì)講解。

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";
                // 獲取當(dāng)前加載的所有類
                $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 也順帶一起注冊了,方便對拓展的調(diào)用。

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

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

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

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

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

疑問: composer_static 的參數(shù)代表是什么?
 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__ . "/../.." ,
              ……
)

直接命名空間全名與目錄的映射,簡單粗暴,也導(dǎo)致這個數(shù)組相當(dāng)?shù)拇蟆?/p>

PSR4 標(biāo)準(zhǔn)頂級命名空間映射數(shù)組:
  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 標(biāo)準(zhǔn)頂級命名空間映射用了兩個數(shù)組,第一個是用命名空間第一個字母作為前綴索引,然后是 頂級命名空間,但是最終并不是文件路徑,而是 頂級命名空間的長度。為什么呢?

因為 PSR4 標(biāo)準(zhǔn)是用頂級命名空間目錄替換頂級命名空間,所以獲得頂級命名空間的長度很重要。

具體說明這些數(shù)組的作用:

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

"SymfonyPolyfillMbstring" => 26,

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

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

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

注: 其實作為一個web框架,composer里面的東西,不應(yīng)該由ThinkPHP關(guān)心的,但由于 TP5 自己原生的框架包 的設(shè)計沒有完全包容 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空間這個靜態(tài)變量中。到時候方便我們使用命名空間進(jìn)行調(diào)用。

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

在 TP5 代碼下執(zhí)行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文件,生成的類庫映射文件會掃描系統(tǒng)目錄和應(yīng)用目錄的類庫。在之后碰到了之后直接拿來用,提高系統(tǒng)自動加載的性能。

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

使用自動加載

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

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

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

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

在這時的狀態(tài)里 Error 不存在,所有會進(jìn)入我們的自動加載方法中重新試一下。

//函數(shù)整體內(nèi)容
public static function autoload($class)
    {
        if (isset(self::$classAlias[$class])) {
            return class_alias(self::$classAlias[$class], $class);
        }

        if ($file = self::findFile($class)) {

            // Win環(huán)境嚴(yán)格區(qū)分大小寫
            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);
        }

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

if ($file = self::findFile($class)) {

            // Win環(huán)境嚴(yán)格區(qū)分大小寫
            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 會提升性能的原因),如果沒有緩存就配合我們之前存儲映射關(guān)系的靜態(tài)數(shù)組prefixDirsPsr4,和 prefixLengthsPsr4來找尋文件的目錄,速度會相對慢很多。 如果沒有找到那么就返回空, spl_autoload_register 會判斷沒有找到該類,拋出錯誤。

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

這里主要是擔(dān)心在window環(huán)境下,路徑名稱大小寫沒分,所以我們根據(jù)linux的目錄規(guī)則重寫了文件路徑

之后再加我們的目錄文件

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/31572.html

相關(guān)文章

  • Java相關(guān)

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

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

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

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

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

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

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

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

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

    wangzy2019 評論0 收藏0

發(fā)表評論

0條評論

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