溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

composer自動(dòng)加載機(jī)制指的是什么

發(fā)布時(shí)間:2021-01-18 09:39:59 來(lái)源:億速云 閱讀:170 作者:小新 欄目:軟件技術(shù)

這篇文章主要介紹了composer自動(dòng)加載機(jī)制指的是什么,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

正文

1.了解一下spl_autoload_register

首先查一下php官方手冊(cè):
composer自動(dòng)加載機(jī)制指的是什么
(偷懶可以只看紅色部分即可)

是不是看著一知半解?
來(lái)用白話(huà)文來(lái)翻譯一下:

我們new一個(gè)類(lèi)的話(huà),必須先require或者include類(lèi)的文件,如果沒(méi)有加載進(jìn)來(lái)則會(huì)報(bào)錯(cuò)。這產(chǎn)生一個(gè)問(wèn)題:那這樣的話(huà)文件的頭部到處都是requies和include,明顯不符合程序員必須"偷懶"尿性。
為了不需要require或者include類(lèi)文件也能正常的new一個(gè)類(lèi),出現(xiàn)了自動(dòng)加載機(jī)制。spl_autoload_register這個(gè)函數(shù)就專(zhuān)門(mén)干這個(gè)事的。

從截圖得知,此函數(shù)有三個(gè)參數(shù):

參數(shù)詳解
autoload_function這里填的是一個(gè)***"函數(shù)"的名稱(chēng)***,字符串或者數(shù)組,這個(gè)函數(shù)的功能就是把需要new的文件require或者include盡量,避免new的時(shí)候報(bào)錯(cuò)。簡(jiǎn)單的說(shuō)就是要你封裝一個(gè)***自動(dòng)加載文件的函數(shù)***
throw當(dāng)自動(dòng)加載的函數(shù)無(wú)法注冊(cè)的時(shí)候,是否拋異常
prepend是否添加函數(shù)到函數(shù)隊(duì)列之首,如果是true則為首,否則尾部

來(lái)一波代碼,印象深刻一些:

//文件 testClass.php ,即將new的類(lèi)
class TestClass{
    public function __construct() {
        echo '你已經(jīng)成功new了我了';
    }
}

//文件autoloadDemo.php文件
spl_autoload_register('autoLoad_function', true, true);
function autoLoad_function($class_name){
    echo "所有的require或者include文件工作都交給我吧!\r\n";
    $class_filename = "./{$class_name}.php";
    echo "我來(lái)加載{$class_filename}文件\r\n";
    require_once("./{$class_name}.php");
}
$obj_demo = new TestClass();

輸出:

所有的require或者include文件工作都交給我吧!
我來(lái)加載testClass.php文件
你已經(jīng)成功new了我了

明白了這個(gè)加載的原理,看下文就順利多了。

2.composer update發(fā)生的故事

將自動(dòng)加載之前,必須要先說(shuō)一下composer update,這里頭承載了自動(dòng)加載的前提。

composer項(xiàng)目都包含一個(gè)composer.json的配置文件。
composer自動(dòng)加載機(jī)制指的是什么
這里頭有一個(gè)關(guān)鍵的字段"autoload",包含psr-4和files兩個(gè)字段。

psr-4:說(shuō)明是基于psr-4規(guī)范的類(lèi)庫(kù),都支持自動(dòng)加載,只要在后面的對(duì)象中以**“命名空間:路徑”**的方式寫(xiě)入自己的類(lèi)庫(kù)信息即可。
files:這就就更直接了,寫(xiě)入路徑就自動(dòng)加載。

按照以上配置每回composer update之后呢,都會(huì)更新一個(gè)很重要的文件:./vender/composer/autoload_psr4.php。
composer自動(dòng)加載機(jī)制指的是什么

這個(gè)文件只做了一件事情:把命名空間和文件路徑對(duì)應(yīng)起來(lái),這樣后續(xù)自動(dòng)加載就有映射根據(jù)了。

3.追蹤一下composer的自動(dòng)加載

composer的故事從唯一的一個(gè)require說(shuō)起:

require '../vendor/autoload.php'

這個(gè)腳本執(zhí)行了一個(gè)函數(shù):

ComposerAutoloaderInitd9b31141b114fcbee3cf55d0e97b7f87::getLoader()

繼續(xù)跟getloader函數(shù)做了什么?

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

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

    $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\ComposerStaticInitd9b31141b114fcbee3cf55d0e97b7f87::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\ComposerStaticInitd9b31141b114fcbee3cf55d0e97b7f87::$files;
    } else {
        $includeFiles = require __DIR__ . '/autoload_files.php';
    }
    foreach ($includeFiles as $fileIdentifier => $file) {
        composerRequired9b31141b114fcbee3cf55d0e97b7f87($fileIdentifier, $file);
    }

    return $loader;
}

這個(gè)函數(shù)主要做了兩件事情:
1.將各種存有命名空間和文件映射關(guān)系的文件autoload_xxx.php加載了進(jìn)來(lái),并作了一些處理(比如:setPsr4將相關(guān)映射加載了進(jìn)去,這個(gè)留意下,下文會(huì)有呼應(yīng)。)。
2.注冊(cè)了函數(shù)register

繼續(xù)跟蹤register做了什么:

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

原來(lái)調(diào)用了spl_autoload_register函數(shù),當(dāng)類(lèi)沒(méi)加載的時(shí)候使用loadClass來(lái)加載類(lèi)。(這個(gè)前文講的很清楚了,應(yīng)該很熟了)

繼續(xù)跟蹤loadClass實(shí)現(xiàn):

public function loadClass($class) {
	if ($file = $this->findFile($class)) {
		includeFile($file);
		return true;
	}
}

大概可以看出,是做了文件的include。
繼續(xù)跟蹤下是怎么查找文件的,看findFile函數(shù):

public function findFile($class) {
    // class map lookup
    if (isset($this->classMap[$class])) {
        return $this->classMap[$class];
    }
    if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
        return false;
    }
    if (null !== $this->apcuPrefix) {
        $file = apcu_fetch($this->apcuPrefix.$class, $hit);
        if ($hit) {
            return $file;
        }
    }

    $file = $this->findFileWithExtension($class, '.php');

    // Search for Hack files if we are running on HHVM
    if (false === $file && defined('HHVM_VERSION')) {
        $file = $this->findFileWithExtension($class, '.hh');
    }

    if (null !== $this->apcuPrefix) {
        apcu_add($this->apcuPrefix.$class, $file);
    }

    if (false === $file) {
        // Remember that this class does not exist.
        $this->missingClasses[$class] = true;
    }

    return $file;
}

這個(gè)函數(shù)做了一件事:就是尋找類(lèi)從上文的autoload_xxx.php初始化的數(shù)據(jù)中來(lái)尋找映射的文件路徑。
其中這個(gè)函數(shù)findFileWithExtension,適用于尋找psr-4規(guī)范的文件的映射信息的。

繼續(xù)跟蹤findFileWithExtension:

private function findFileWithExtension($class, $ext) {
    // PSR-4 lookup
    $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;

    $first = $class[0];
    if (isset($this->prefixLengthsPsr4[$first])) {
        $subPath = $class;
        while (false !== $lastPos = strrpos($subPath, '\\')) {
            $subPath = substr($subPath, 0, $lastPos);
            $search = $subPath.'\\';
            if (isset($this->prefixDirsPsr4[$search])) {
                $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
                foreach ($this->prefixDirsPsr4[$search] as $dir) {
                    if (file_exists($file = $dir . $pathEnd)) {
                        return $file;
                    }
                }
            }
        }
    }

    // PSR-4 fallback dirs
    foreach ($this->fallbackDirsPsr4 as $dir) {
        if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
            return $file;
        }
    }

    // PSR-0 lookup
    if (false !== $pos = strrpos($class, '\\')) {
        // namespaced class name
        $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
            . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
    } else {
        // PEAR-like class name
        $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
    }

    if (isset($this->prefixesPsr0[$first])) {
        foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
            if (0 === strpos($class, $prefix)) {
                foreach ($dirs as $dir) {
                    if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
                        return $file;
                    }
                }
            }
        }
    }

    // PSR-0 fallback dirs
    foreach ($this->fallbackDirsPsr0 as $dir) {
        if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
            return $file;
        }
    }

    // PSR-0 include paths.
    if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
        return $file;
    }

    return false;
}

這個(gè)函數(shù)做了件事:將命名空間\類(lèi)這樣的類(lèi)名,轉(zhuǎn)換成目錄名/類(lèi)名.php這樣的路徑,再?gòu)那拔膕etPsr4設(shè)置的映射信息中尋找映射信息,然后完成返回路徑。

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“composer自動(dòng)加載機(jī)制指的是什么”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來(lái)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI