Laravel 源碼解析之 composer 自動(dòng)加載

在研究 Laravel 源碼的過程中,我遇到的第一個(gè)問題就是:Laravel 的中使用到的那些類是如何被加載進(jìn)來的蚜锨?

在 Laravel 的入口文件的第二行代碼中,引入了 bootstrap 文件夾下的 app.php 文件屑彻。而在這個(gè)文件的開頭嘱腥,一個(gè)名為 Application 的類就被初始化录别,這個(gè)文件在此之前并未引入,程序順利執(zhí)行邻吞。

很顯然组题,這個(gè)自動(dòng)加載的問題是在入口文件的第一行被解決的。在第一行引入的文件中抱冷,引入了 vendor 文件夾的 autoload.php 文件崔列。這個(gè)文件與 composer 有關(guān),Laravel 的自動(dòng)加載是借助了 composer旺遮。

composer 自動(dòng)加載

那么 composer 是如何做到自動(dòng)加載的呢赵讯?

打開 autoload.php 文件,這里面只有兩行代碼耿眉。第一行引入了一個(gè)文件边翼,第二行調(diào)用了該文件中的類的 getLoader 方法。ComposerAutoloaderInit5ba1fc8bf6c79636a218962c1a6da048 這個(gè)類名之所以看起來奇怪鸣剪,是因?yàn)橐乐诡惷麤_突而使用了 hash组底。

<?php

// autoload.php @generated by Composer

require_once __DIR__ . '/composer/autoload_real.php';

return ComposerAutoloaderInit5ba1fc8bf6c79636a218962c1a6da048::getLoader();

在 getLoader 方法中,\Composer\Autoload\ClassLoader 被初始化為 $loader筐骇,然后 $loader 這個(gè)加載器的四個(gè)屬性 $prefixLengthsPsr4债鸡、$prefixDirsPsr4、$prefixesPsr0铛纬、$classMap 被依次填充厌均,前兩個(gè)對(duì)應(yīng)著 psr-4 規(guī)范,后面兩個(gè)分別對(duì)應(yīng) psr-0 和 classMap告唆。

    public static function getLoader()
    {
        if (null !== self::$loader) {
            return self::$loader;
        }

        spl_autoload_register(array('ComposerAutoloaderInit5ba1fc8bf6c79636a218962c1a6da048', 'loadClassLoader'), true, true);
        self::$loader = $loader = new \Composer\Autoload\ClassLoader();
        spl_autoload_unregister(array('ComposerAutoloaderInit5ba1fc8bf6c79636a218962c1a6da048', 'loadClassLoader'));

        $includePaths = require __DIR__ . '/include_paths.php';
        array_push($includePaths, get_include_path());
        set_include_path(join(PATH_SEPARATOR, $includePaths));

        $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
        if ($useStaticLoader) {
            require_once __DIR__ . '/autoload_static.php';

            call_user_func(\Composer\Autoload\ComposerStaticInit5ba1fc8bf6c79636a218962c1a6da048::getInitializer($loader));
        } else {
            $map = require __DIR__ . '/autoload_namespaces.php';
            foreach ($map as $namespace => $path) {
                $loader->set($namespace, $path);
            }

            $map = require __DIR__ . '/autoload_psr4.php';
            foreach ($map as $namespace => $path) {
                $loader->setPsr4($namespace, $path);
            }

            $classMap = require __DIR__ . '/autoload_classmap.php';
            if ($classMap) {
                $loader->addClassMap($classMap);
            }
        }

        $loader->register(true);

        if ($useStaticLoader) {
            $includeFiles = Composer\Autoload\ComposerStaticInit5ba1fc8bf6c79636a218962c1a6da048::$files;
        } else {
            $includeFiles = require __DIR__ . '/autoload_files.php';
        }
        foreach ($includeFiles as $fileIdentifier => $file) {
            composerRequire5ba1fc8bf6c79636a218962c1a6da048($fileIdentifier, $file);
        }

        return $loader;
    }

填充的內(nèi)容來自于 vendor/composer 文件夾下的這三個(gè)文件:autoload_classmap棺弊、autoload_namespaces、autoload_psr4擒悬。打開這些文件模她,每一個(gè)文件都返回了一個(gè)包含了很多文件路徑的數(shù)組。這些則來自于 composer.json茄螃。

    "autoload": {
        "classmap": [
            "database"
        ],
        "psr-4": {
            "App\\": "app/"
        }
    },
    "autoload-dev": {
        "classmap": [
            "tests/TestCase.php"
        ]
    },

不只是 Laravel 的根目錄存在 composer.json缝驳,vendor 文件夾下每一個(gè)由 composer 安裝的依賴庫,都存在著一個(gè)這樣的文件归苍。

$loader 加載器被填充后用狱,調(diào)用了它的 register 方法,在這個(gè)方法中拼弃,使用了 spl_autoload_register 注冊(cè)該類的 loadClass 方法作為 __autoload 的實(shí)現(xiàn)夏伊。需要用到一個(gè)類的時(shí)候,就會(huì)調(diào)用 loadClass 方法吻氧。

    public function register($prepend = false)
    {
        spl_autoload_register(array($this, 'loadClass'), true, $prepend);
    }

緊接著溺忧,引入了 autoload_files咏连,與其他三個(gè)不同,它返回的數(shù)組鲁森,數(shù)組中定義的多個(gè)文件會(huì)被提前加載祟滴,而不是用到時(shí)才加載。如其中的 '/laravel/framework/src/Illuminate/Foundation/helpers.php'歌溉、'/laravel/framework/src/Illuminate/Support/helpers.php'垄懂。正是由于這兩個(gè)文件被提前加載,其中的定義的框架方法才可以被在項(xiàng)目中任意使用痛垛。

    // vendor/laravel/framework/composer.json
    "autoload": {
        "files": [
            "src/Illuminate/Foundation/helpers.php",
            "src/Illuminate/Support/helpers.php"
        ],
        "psr-4": {
            "Illuminate\\": "src/Illuminate/"
        }
    },

最后草慧,$loader 被返回。接下來就可以在項(xiàng)目中沒有顧忌的使用各種類和方法了匙头,而不需要把 include 寫滿每一個(gè)角落漫谷。當(dāng)然,前提是需要符合 psr-4 的規(guī)范蹂析。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末舔示,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子识窿,更是在濱河造成了極大的恐慌斩郎,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件喻频,死亡現(xiàn)場離奇詭異,居然都是意外死亡肘迎,警方通過查閱死者的電腦和手機(jī)甥温,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來妓布,“玉大人姻蚓,你說我怎么就攤上這事∠徽樱” “怎么了狰挡?”我有些...
    開封第一講書人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長释涛。 經(jīng)常有香客問我加叁,道長,這世上最難降的妖魔是什么唇撬? 我笑而不...
    開封第一講書人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任它匕,我火速辦了婚禮,結(jié)果婚禮上窖认,老公的妹妹穿的比我還像新娘豫柬。我一直安慰自己告希,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開白布烧给。 她就那樣靜靜地躺著燕偶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪础嫡。 梳的紋絲不亂的頭發(fā)上杭跪,一...
    開封第一講書人閱讀 52,268評(píng)論 1 309
  • 那天,我揣著相機(jī)與錄音驰吓,去河邊找鬼涧尿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛檬贰,可吹牛的內(nèi)容都是我干的姑廉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼翁涤,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼桥言!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起葵礼,我...
    開封第一講書人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤枝笨,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后拳球,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體集畅,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年届谈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了枯夜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡艰山,死狀恐怖湖雹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情曙搬,我是刑警寧澤摔吏,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站纵装,受9級(jí)特大地震影響征讲,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜搂擦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一稳诚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瀑踢,春花似錦扳还、人聲如沸才避。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽桑逝。三九已至,卻和暖如春俏让,著一層夾襖步出監(jiān)牢的瞬間楞遏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來泰國打工首昔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留寡喝,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓勒奇,卻偏偏與公主長得像预鬓,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子赊颠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容