您好,登錄后才能下訂單哦!
這篇文章主要介紹了composer自動(dòng)加載機(jī)制指的是什么,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
首先查一下php官方手冊(cè):
(偷懶可以只看紅色部分即可)
是不是看著一知半解?
來(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è)加載的原理,看下文就順利多了。
將自動(dòng)加載之前,必須要先說(shuō)一下composer update,這里頭承載了自動(dòng)加載的前提。
composer項(xiàng)目都包含一個(gè)composer.json的配置文件。
這里頭有一個(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。
這個(gè)文件只做了一件事情:把命名空間和文件路徑對(duì)應(yīng)起來(lái),這樣后續(xù)自動(dòng)加載就有映射根據(jù)了。
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í)!
免責(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)容。