說明:本文主要以Laravel的容器類Container爲例作簡單說明Composer的自動加載機制。php
一、初始化一個composer項目html
在一個空目錄下composer安裝Laravel的容器Container包:laravel
composer require illuminate/container
而後在該目錄下新建一個index.php文件,而後分析下Container類爲什麼能被實例化:json
<?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);
二、分析下composer加載類的流程數組
使用composer最大的好處是隻需最開始require一個autoload.php文件,就能夠new你所須要的類了,再也不須要傳統的方式A文件內各類include跳到B文件又各類include,很是頭疼。
app
Composer按照四種規範來加載文件:composer
ComposerAutoloaderInit88609474169d8656473fa0223c682a7a這個類是composer爲了防止類衝突搞了一個命名ComposerAutoloaderInit+hash,無論咋樣,require_once這個類後須要返回的是一個加載器$loader,而這個加載器通過四種規範遍歷後,由null被填充爲含有各類變量值的ClassLoader對象。ide
若是仔細觀察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就包含了命名空間路徑映射的數組值,其他私有變量就是空。ui
最後返回一個加載器$loader,而後須要實例化一個類時,就會根據loadClass($class)來尋找對應的文件,看下文。
$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的字符串和數組這些基礎知識新開篇章,到時見。