Laravel學習筆記之Composer自動加載

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

注:上篇文章基於Laravel Task-Scheduler定時發送郵件小程序聊到本打算接下來聊聊Laravel的設計模式,不過做者水平有限還需提升一段時間,故暫不先誤人子弟了。此次先一塊兒聊聊Composer的自動加載機制,並以Laravel的Container爲例舉例。html

Composer的自動加載機制

一、初始化一個composer項目
在一個空目錄下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,很是頭疼。segmentfault

Composer按照四種規範來加載文件:設計模式

  • psr-4api

  • psr-0(這種規範某些部分不是很優雅)數組

  • classmap(命名空間和文件路徑的映射)app

  • 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包只包含IlluminateContainer和IlluminateContracts,且都是psr-4規範,則私有變量$prefixLengthsPsr4和$prefixDirsPsr4就包含了命名空間路徑映射的數組值,其他私有變量就是空。

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

Container類的實例化過程

圖片描述

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

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

總之,當實例化一個類時,這個$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的IlluminateContainer包爲例具體說明實例化類時是如何找到其文件的,並講述如何自定義本身的類並經過Composer來註冊和加載。過兩天還想結合PHP的字符串和數組這些基礎知識新開篇章,到時見。

歡迎關注Laravel-China

RightCapital招聘Laravel DevOps

相關文章
相關標籤/搜索