日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > php >内容正文

php

分析ThinkPHP5的源码(1) : 类的自动加载

發布時間:2023/12/20 php 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 分析ThinkPHP5的源码(1) : 类的自动加载 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前文

Composer 下載ThinkPHP5.1的源碼,每個框架它都必須都有一個“類的自動加載”機制 ,我們都知道PHP引入文件是需要require 、 include 才能使用別的類文件中的方法。

比如我需要寫一個公共文件 model.php

include "model.php" include "model2.php"class User {//code.. }

但是!如何當公共類庫文件很多的時候,每次都需要手動引入,就顯得非常麻煩,不利于/不方便維護管理。
所以PHP引入了一個spl_autoload_register() 的類自動加載,TP框架就是借助了 spl_autoload_register() 來完成類的自動加載。

TP5框架入口加載機制

學習框架源碼的第一步,先找到入口文件 public/index.php ,然后一步步跟進流程,看下代碼執行的過程。

  • 第一行:定義命名空間就不贅述了。。
  • 第二行:去加載基礎文件 base.php ,是位于上一層目錄的 think目錄下

打開Base.php ,第16行就會去加載 Loader.php 文件 (就是TP5自動加載的類庫) ,Loader.php 是TP5封裝的底層基礎類庫。

再引用了核心文件 Loader.php

調用類庫的 Loader::register() 的方法

發現都用了spl_autoload_register()的系統函數,其他框架也是同理。
都是會在框架的第一步“入門文件”就進行類的自動加載機制,針對底層進行封裝。

TP5中的Loader::register() 其實做了2件事:

  • 內部自定義一個autoload() 去進行框架的底層深度封裝
  • 為了支持 Composer 自動加載 安裝第三方的類庫插件(Vendor),都是遵循PSR-4的風格統一,那么加載composer類的 autoload_static.php 后,再去加載對應的插件類庫。

分析Loader::register的執行流程

如下截圖:

  • 分析TP5執行 Loader::register() 的注冊自動加載方法 ,( 是調用不存在的類的時候才會執行spl_autoload_register())

  • 運用3元運算符,如果有參數就執行其他自定義類,沒就 加載本類的autoload() 方法

  • 調用 self::gerRootPath() 獲取項目的根目錄

  • 這里就是走 Composer的加載機制,然后組織一個Vendor的決定路徑 ,self::$composerPath

  • 判斷是否有Vendor的目錄,再判斷是否有auto_static的文件 ,有就加載composer目錄下的auto_static.php

  • 分析Composer自動加載——類文件

    在邏輯往下走,判斷是否有Vendor的目錄,再判斷是否有auto_static的文件 ,有就加載composer目錄下的auto_static.php

    auto_static.php

    發現定義了2個屬性分別是: $prefixLengthsPsr4 、$prefixDirsPsr4 ,這是什么意思呢?


    定義數組,有個key和value,比如 $prefixLengthsPsr4 (PSR4的長度)

    • t key代表一個命名空間 ,代表think\composer\ 命名空間 ,首字母代表類,把某些類放進去來,15 代表字符的長度。
    • a key也是代表一個命名空間,代表:app ,用首字母代表,把某些類放進去, 4是這個字符的長度。

    2個斜線是轉義字符,比如 think\\composer\\ 等同于 think\composer\

    $prefixDirsPsr4 把每個命名空間的類對應的目錄列出來

    • 比如think\composer 這個命名空間 在src下
    • app\\ 這個命名空間就在根目錄的application

      比如通過 Compsoe r安裝 swoole、workermam、phpexcel 就把相應的規則追加數組上 填進來。

    總結: composer的統一加載機制的地方,每次composer新類庫的時候,都會往這個屬性追加 命名空間 以及類庫的目錄路徑 。

    分析Composer自動加載——屬性賦值

    回到Loader::register()方法。

    // 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);}}// 注冊命名空間定義self::addNamespace(['think' => __DIR__,'traits' => dirname(__DIR__) . DIRECTORY_SEPARATOR . 'traits',]);

    再返回 Loader::register() 方法接著放下分析:

    如果存在Vendor目錄,再判斷是否有 composer_static.php ,有就執行如下:

    執行了 get_declared_classes 這個系統函數,返回由當前腳本中已定義類的名字組成的數組。

    我們打印這個get_declared_classes

    得到目前所有加載的類,最后require加載的是 composer類

    所以,我們上面的 array_pop 彈出最后一個元素,賦值后的 $composerClass ,就是composer的類。


    這個命令空間那么長的其實就是 composer目錄下的autoload_static.php

    再繼續往下執行

    property_exists : 檢查對象或類是否具有該屬性

    我們知道autoload_static.php 存在有

    • prefixLengthsPsr4
    • $prefixDirsPsr4
    • $classMap

    等一眾的方法,composer的 stacis.php這些屬性以及值 ,再賦值作為Loader類的某個屬性再處理。

    上面的寫法等同 :

    self::prefixLengthsPsr4 self::prefixDirsPsr4

    打印這些屬性返回:

    為什么這樣去做?后續要集合多個屬性再Map,加載文件的時候用這些屬性。

    總結: 把composere下的auto_static的PSR4的屬性以及值賦值到Loader的PSR4屬性中

    分析Composer自動加載——注冊命名空間

  • 會調用當前Loader::addNamespace() 方法 ,把當前think 跟traits 核心注冊進行。
  • // 注冊命名空間定義 self::addNamespace(['think' => __DIR__,'traits' => dirname(__DIR__) . DIRECTORY_SEPARATOR . 'traits', ]);
  • 進去 addNamespace() 方法,我們打印這個 $namespace 參數。
  • // 注冊命名空間public static function addNamespace($namespace, $path = ''){echo "<pre>";print_r($namespace);exit;if (is_array($namespace)) {foreach ($namespace as $prefix => $paths) {self::addPsr4($prefix . '\\', rtrim($paths, DIRECTORY_SEPARATOR), true);}} else {self::addPsr4($namespace . '\\', rtrim($path, DIRECTORY_SEPARATOR), true);}}


    3. 再接下來,無論是不是數組,都再把命名空間拼接組裝好,再調用self::addPsr4()
    4. 查看 addPsr4() 方法

    注冊的時候走的是“296” 行 。

    因為之前 self::$prefixDirsPsr4 里的屬性只是composer的autp_static.php 上的,只有 think\ 跟 app\ ,并沒有think 跟traits 這2個屬性。

    public static $prefixDirsPsr4 = array ('think\\composer\\' => array (0 => __DIR__ . '/..' . '/topthink/think-installer/src',),'app\\' => array (0 => __DIR__ . '/../..' . '/application',),);


    6. 這樣就完成 think、traits下的命名空間注冊到Loader類的PSR4屬性中。

    加載類庫映射文件

    再往下執行:

  • 我們在根目錄的runtime 并沒有classmap.php的文件 ,我們可以通過命令生成這個文件
  • php think optimize:autoload
  • 這時候runtime下就有classmap.php ,就是存放一些命名空間映射的文件
  • <?php /*** 類庫映射*/return ['app\\index\\controller\\Index' => '/Users/limingqiang/project_php/localhost_pro/tp51_source_code/application/' . 'index/controller/Index.php','think\\App' => '/Users/limingqiang/project_php/localhost_pro/tp51_source_code/thinkphp/library/' . '/think/App.php','think\\Build' => '/Users/limingqiang/project_php/localhost_pro/tp51_source_code/thinkphp/library/' . '/think/Build.php','think\\Cache' => '/Users/limingqiang/project_php/localhost_pro/tp51_source_code/thinkphp/library/' . '/think/Cache.php','think\\Collection' => '/Users/limingqiang/project_php/localhost_pro/tp51_source_code/thinkphp/library/' . '/think/Collection.php','think\\Config' => '/Users/limingqiang/project_php/localhost_pro/tp51_source_code/thinkphp/library/' . '/think/Config.php','think\\Console' => '/Users/limingqiang/project_php/localhost_pro/tp51_source_code/thinkphp/library/' . '/think/Console.php','think\\Container' => '/Users/limingqiang/project_php/localhost_pro/tp51_source_code/thinkphp/library/' . '/think/Container.php',//code..... ]
  • 進入這個 self::addClassMap() 方法,看到把當前classmap.php的數組內容賦值到一個 Loader類的**$classMap** 屬性中。
  • 總結: 把tp5的核心的 think 和 traits 命名空間注冊到PSR4里,方便后續調用,實在屬性多個數組統一自動加載。

    自動加載extend目錄

    再往下執行

    進去 self::addAutoLoadDir() 方法:

    // 注冊自動加載類庫目錄public static function addAutoLoadDir($path){self::$fallbackDirsPsr4[] = $path;}

    把當前extend的目錄也加載到 Loader類 $fallbackDirsPsr4 的屬性中。

    總結

    • prefixDirsPsr4 (對應類的目錄)
    • prefixLengthsPsr4 (對應類的命名長度)
    • fallbackDirsPsr4 (對應extend的目錄)

    我們拿到很多變量成員、命令空間、目錄路徑等都賦值到 Loader類的多個PSR4的屬性中。

    后續再拿這些屬性做自動加載配置。

    總結

    以上是生活随笔為你收集整理的分析ThinkPHP5的源码(1) : 类的自动加载的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。