Laravel 學習筆記之 Composer 自動加載


說明:本文主要以Laravel的容器類Container為例做簡單說明Composer的自動加載機制。

Composer的自動加載機制

1、初始化一個composer項目

在一個空目錄下composer安裝Laravel的容器Container包:

composer require illuminate/container

然后在該目錄下新建一個index.php文件,然后分析下Container類為何能被實例化:

<?php
/**
 * Created by PhpStorm.
 * User: liuxiang
 * Date: 16/5/12
 * Time: 19:59
 */
require_once __DIR__.'/vendor/autoload.php';

$container = new Illuminate\Container\Container();
var_dump($container);

2、分析下composer加載類的流程

圖片描述

使用composer最大的好處是只需最開始require一個autoload.php文件,就可以new你所需要的類了,不再需要傳統的方式A文件內各種include跳到B文件又各種include,非常頭疼。

Composer按照四種規范來加載文件:

  • psr-4
  • psr-0(這種規范某些部分不是很優雅)
  • classmap(命名空間和文件路徑的映射)
  • files

ComposerAutoloaderInit88609474169d8656473fa0223c682a7a這個類是composer為了防止類沖突搞了一個命名ComposerAutoloaderInit+hash,不管咋樣,require_once這個類后需要返回的是一個加載器$loader,而這個加載器經過四種規范遍歷后,由null被填充為含有各種變量值的ClassLoader對象。

如果仔細觀察autoload_classmap.php、autoload_namespaces.php、autoload_psr4.php和autoload_files(這里用了Container包是沒有這個文件的,但Laravel整個項目是有的)文件后,這些都按照對應的規范返回要么命名空間與路徑的映射,要么完整路徑與某個哈希的映射。

從上圖中能看出這個composer初始化路徑的流程,重點是ClassLoader這個類的loadClass($class)這個方法,是通過spl_autoload_register這個PHP自動加載函數來注冊到autoload函數棧中,最后返回一個$loader加載器,而這個加載器是包含一些私有變量的,由於本Container包只包含Illuminate\Container和Illuminate\Contracts,且都是psr-4規范,則私有變量$prefixLengthsPsr4和$prefixDirsPsr4就包含了命名空間路徑映射的數組值,其余私有變量就是空。

最后返回一個加載器$loader,然后需要實例化一個類時,就會根據loadClass($class)來尋找對應的文件,看下文。

Container類的實例化過程#

圖片描述

$loader這個加載器已經有了,而且它還是塞滿了各種私有變量,這些變量值為命名空間路徑映射或者路徑哈希映射等,當然這里只有命名空間路徑映射這種psr-4規范了。也就是說,一句require_once這個autoload.php文件后就拿到了一個飽滿的$loader,然后現在開始new一個類Container,那如何找到這個Container.php文件路徑的呢?

從第二個序列圖就可看出,首先調用ClassLoader中的loadClass()這個函數來找文件路徑,傳入的$class變量值是“Illuminate\Container\Container”這個字符串,然后又繼續調用findFile($class)函數先做classmap查找,然后進入findFileWithExtension($class,'.php')中做psr-4/psr-0查找,其實就是搜尋這些私有變量值,比如這里Container類是psr-4規范,那就去$prefixLengthsPsr4/$prefixDirsPsr4這些psr-4私有變量中查找文件絕對路徑,返回一個$file,再include下就等於這個類可以被實例化了。當然,這里Container.php文件絕對路徑被找到后,發現它還實現了一個接口ContractContainer,那就再去同樣方式找這個文件:psr-4根據命名空間Illuminate\Contracts\Container\Container去找這個接口對應的絕對路徑。

總之,當實例化一個類時,這個$loader就去根據四種規范找該文件的絕對路徑,如果這個類還有繼承或實現關系,那就遞歸找。

自定義一個類文件#

現在自己寫一個類文件,當實例化的時候,然后讓composer來自動加載,怎么做?

修改composer.json文件:

{
    "require": {
        "illuminate/container": "^5.2"
    },
    "autoload": {
        "psr-4": {
            "App\\": "app/"
        }
    }
}

這里按照psr-4規范來,然后在項目根目錄下使用命令:

composer install

發現autoload_psr4.php文件會多一個數組值:

return array(
    'Illuminate\\Contracts\\' => array($vendorDir . '/illuminate/contracts'),
    'Illuminate\\Container\\' => array($vendorDir . '/illuminate/container'),
    'App\\' => array($baseDir . '/app'),
);

然后在項目根目錄下新建文件:

// app/Test/Test.php文件
<?php
/**
 * Created by PhpStorm.
 * User: liuxiang
 * Date: 16/5/12
 * Time: 21:52
 */

namespace App\Test;

class Test
{
    public function index()
    {
        echo "This is a custom class which will be autoload by composer\n";
    }
}

在index.php文件中就可以實例化Test類並調用其對象函數了:

require_once __DIR__.'/vendor/autoload.php';

//$container = new Illuminate\Container\Container();
//var_dump($container);

$test = new App\Test\Test();
$test->index();

終端執行輸出:
圖片描述

通過在Composer中注冊下,Composer就可以幫我們找到類文件,就不需要自己各種include,只需開始一句require_once就行,真的很方便。

One More Thing...

配置Xdebug。強烈推薦在自己的IDE中配置Xdebug,作者使用PHPStorm,並配置了Xdebug,這會提高閱讀源碼的效率。具體操作流程可以谷歌文檔,應該很多,Netbeans或者ZendStudio應該也有很多配置文檔。如果有配置不成功的,可以在本文留言下問題,作者會盡量解答。

PlantUML插件的安裝。本文UML序列圖用的是PlantUML這個插件來做的,還比較好用,推薦下。可以在PHPStorm插件庫里搜UML就行,然后新建一個文件時會發現多了好幾個UML選項,並且還有一個PlantUML窗口:
圖片描述
圖片描述

關於這個PlantUML有一篇文章還挺好:Create Beautiful UML Diagrams in Minutes from the JetBrains IDE,還有它的官網(就是有各種廣告):PlantUML

總結:本文主要聊了下Composer的加載流程,並以Laravel的Illuminate\Container包為例具體說明實例化類時是如何找到其文件的,並講述如何自定義自己的類並通過Composer來注冊和加載。過兩天還想結合PHP的字符串和數組這些基礎知識新開篇章,到時見。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM