當(dāng)前位置:首頁(yè) > 芯聞號(hào) > 充電吧
[導(dǎo)讀]Composer?是PHP的一個(gè)包依賴管理工具,類似Ruby中的RubyGems或者Node中的NPM,它并非官方,但現(xiàn)在已經(jīng)非常流行。此文并不介紹如何使用Composer,而是關(guān)注于它的autolo

Composer?是PHP的一個(gè)包依賴管理工具,類似Ruby中的RubyGems或者Node中的NPM,它并非官方,但現(xiàn)在已經(jīng)非常流行。此文并不介紹如何使用Composer,而是關(guān)注于它的autoload的內(nèi)容吧。

舉例來(lái)說(shuō),假設(shè)我們的項(xiàng)目想要使用?monolog?這個(gè)日志工具,就需要在composer.json里告訴composer我們需要它:

{
??"require":?{
????"monolog/monolog":?"1.*"
??}
}

之后執(zhí)行:

php composer.phar install

好,現(xiàn)在安裝完了,該怎么使用呢?Composer自動(dòng)生成了一個(gè)autoload文件,你只需要引用它

require '/path/to/vendor/autoload.php';

然后就可以非常方便的去使用第三方的類庫(kù)了,是不是感覺(jué)很棒?。?duì)于我們需要的monolog,就可以這樣用了:

use?MonologLogger;
use?MonologHandlerStreamHandler;

//?create?a?log?channel
$log?=?new?Logger('name');
$log->pushHandler(new?StreamHandler('/path/to/log/log_name.log',?Logger::WARNING));

//?add?records?to?the?log
$log->addWarning('Foo');
$log->addError('Bar');

在這個(gè)過(guò)程中,Composer做了什么呢?它生成了一個(gè)autoloader,再根據(jù)各個(gè)包自己的autoload配置,從而幫我們進(jìn)行自動(dòng)加載的工作。(如果對(duì)autoload這部分內(nèi)容不太了解,可以看我之前的?一篇文章

)接下來(lái)讓我們看看Composer是怎么做的吧。

對(duì)于第三方包的自動(dòng)加載,Composer提供了四種方式的支持,分別是 PSR-0和PSR-4的自動(dòng)加載(我的一篇文章也有介紹過(guò)它們),生成class-map,和直接包含files的方式。

PSR-4是composer推薦使用的一種方式,因?yàn)樗资褂貌⒛軒?lái)更簡(jiǎn)潔的目錄結(jié)構(gòu)。在composer.json里是這樣進(jìn)行配置的:

{
????"autoload":?{
????????"psr-4":?{
????????????"Foo\":?"src/",
????????}
????}
}

key和value就定義出了namespace以及到相應(yīng)path的映射。按照PSR-4的規(guī)則,當(dāng)試圖自動(dòng)加載?"Foo\Bar\Baz"?這個(gè)class時(shí),會(huì)去尋找?"src/Bar/Baz.php"?這個(gè)文件,如果它存在則進(jìn)行加載。注意,?"Foo\"

并沒(méi)有出現(xiàn)在文件路徑中,這是與PSR-0不同的一點(diǎn),如果PSR-0有此配置,那么會(huì)去尋找

"src/Foo/Bar/Baz.php"

這個(gè)文件。

另外注意PSR-4和PSR-0的配置里,"Foo\"結(jié)尾的命名空間分隔符必須加上并且進(jìn)行轉(zhuǎn)義,以防出現(xiàn)"Foo"匹配到了"FooBar"這樣的意外發(fā)生。

在composer安裝或更新完之后,psr-4的配置換被轉(zhuǎn)換成namespace為key,dir path為value的Map的形式,并寫入生成的?vendor/composer/autoload_psr4.php?文件之中。

{
????"autoload":?{
????????"psr-0":?{
????????????"Foo\":?"src/",
????????}
????}
}

最終這個(gè)配置也以Map的形式寫入生成的

vendor/composer/autoload_namespaces.php

文件之中。

Class-map方式,則是通過(guò)配置指定的目錄或文件,然后在Composer安裝或更新時(shí),它會(huì)掃描指定目錄下以.php或.inc結(jié)尾的文件中的class,生成class到指定file path的映射,并加入新生成的?vendor/composer/autoload_classmap.php?文件中,。

{
????"autoload":?{
????????"classmap":?["src/",?"lib/",?"Something.php"]
????}
}

例如src/下有一個(gè)BaseController類,那么在autoload_classmap.php文件中,就會(huì)生成這樣的配置:

'BaseController' => $baseDir . '/src/BaseController.php'

Files方式,就是手動(dòng)指定供直接加載的文件。比如說(shuō)我們有一系列全局的helper functions,可以放到一個(gè)helper文件里然后直接進(jìn)行加載

{
????"autoload":?{
????????"files":?["src/MyLibrary/functions.php"]
????}
}

它會(huì)生成一個(gè)array,包含這些配置中指定的files,再寫入新生成的

vendor/composer/autoload_files.php

文件中,以供autoloader直接進(jìn)行加載。

下面來(lái)看看composer autoload的代碼吧

?$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);

??$includeFiles?=?require?__DIR__?.?'/autoload_files.php';
??foreach?($includeFiles?as?$file)?{
??????composerRequire73612b48e6c3d0de8d56e03dece61d11($file);
??}

??return?$loader;
????}
}

function?composerRequire73612b48e6c3d0de8d56e03dece61d11($file)
{
????require?$file;
}

首先初始化ClassLoader類,然后依次用上面提到的4種加載方式來(lái)注冊(cè)/直接加載,ClassLoader的一些核心代碼如下:

/**
???*?@param?array?$classMap?Class?to?filename?map
???*/
??public?function?addClassMap(array?$classMap)
??{
????if?($this->classMap)?{
??????$this->classMap?=?array_merge($this->classMap,?$classMap);
????}?else?{
??????$this->classMap?=?$classMap;
????}
??}

??/**
???*?Registers?a?set?of?PSR-0?directories?for?a?given?prefix,
???*?replacing?any?others?previously?set?for?this?prefix.
???*
???*?@param?string	???$prefix?The?prefix
???*?@param?array|string?$paths??The?PSR-0?base?directories
???*/
??public?function?set($prefix,?$paths)
??{
????if?(!$prefix)?{
??????$this->fallbackDirsPsr0?=?(array)?$paths;
????}?else?{
??????$this->prefixesPsr0[$prefix[0]][$prefix]?=?(array)?$paths;
????}
??}

??/**
???*?Registers?a?set?of?PSR-4?directories?for?a?given?namespace,
???*?replacing?any?others?previously?set?for?this?namespace.
???*
???*?@param?string	???$prefix?The?prefix/namespace,?with?trailing?'\'
???*?@param?array|string?$paths??The?PSR-4?base?directories
???*
???*?@throws?InvalidArgumentException
???*/
??public?function?setPsr4($prefix,?$paths)
??{
????if?(!$prefix)?{
??????$this->fallbackDirsPsr4?=?(array)?$paths;
????}?else?{
??????$length?=?strlen($prefix);
??????if?('\'?!==?$prefix[$length?-?1])?{
????????throw?new?InvalidArgumentException("A?non-empty?PSR-4?prefix?must?end?with?a?namespace?separator.");
??????}
??????$this->prefixLengthsPsr4[$prefix[0]][$prefix]?=?$length;
??????$this->prefixDirsPsr4[$prefix]?=?(array)?$paths;
????}
??}

??/**
???*?Registers?this?instance?as?an?autoloader.
???*
???*?@param?bool?$prepend?Whether?to?prepend?the?autoloader?or?not
???*/
??public?function?register($prepend?=?false)
??{
????spl_autoload_register(array($this,?'loadClass'),?true,?$prepend);
??}

??/**
???*?Loads?the?given?class?or?interface.
???*
???*?@param??string	$class?The?name?of?the?class
???*?@return?bool|null?True?if?loaded,?null?otherwise
???*/
??public?function?loadClass($class)
??{
????if?($file?=?$this->findFile($class))?{
??????includeFile($file);

??????return?true;
????}
??}

??/**
???*?Finds?the?path?to?the?file?where?the?class?is?defined.
???*
???*?@param?string?$class?The?name?of?the?class
???*
???*?@return?string|false?The?path?if?found,?false?otherwise
???*/
??public?function?findFile($class)
??{
????//這是PHP5.3.0?-?5.3.2的一個(gè)bug??詳見(jiàn)https://bugs.php.net/50731
????if?('\'?==?$class[0])?{
??????$class?=?substr($class,?1);
????}

????//?class?map?方式的查找
????if?(isset($this->classMap[$class]))?{
??????return?$this->classMap[$class];
????}

????//psr-0/4方式的查找
????$file?=?$this->findFileWithExtension($class,?'.php');

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

????if?($file?===?null)?{
??????//?Remember?that?this?class?does?not?exist.
??????return?$this->classMap[$class]?=?false;
????}

????return?$file;
??}

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

????$first?=?$class[0];
????if?(isset($this->prefixLengthsPsr4[$first]))?{
??????foreach?($this->prefixLengthsPsr4[$first]?as?$prefix?=>?$length)?{
????????if?(0?===?strpos($class,?$prefix))?{
??????????foreach?($this->prefixDirsPsr4[$prefix]?as?$dir)?{
????????????if?(file_exists($file?=?$dir?.?DIRECTORY_SEPARATOR?.?substr($logicalPathPsr4,?$length)))?{
??????????????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;
????}
??}


/**
?*?Scope?isolated?include.
?*
?*?Prevents?access?to?$this/self?from?included?files.
?*/
function?includeFile($file)
{
??include?$file;
}


如此最終實(shí)現(xiàn)的原理是在vendor目錄下的


return?ComposerAutoloaderInit5cbf6bb00ad8ca1716a58cda814c22a3::getLoader();

在getLoader中為ComposerAutoloadClassLoader();類填充了信息包括psr-0 psr-4等自動(dòng)加載機(jī)制所需的消息然后調(diào)用

ComposerAutoloadClassLoader()的register函數(shù),進(jìn)行sql_autoload_register的調(diào)用,這樣之后每當(dāng)進(jìn)行類加載的時(shí)候
依次在?psr4前綴中進(jìn)行查找文件目錄,在psr4?fallback目錄中查找,在psr0前綴中查找目錄,在psr0?fallback中查找還有就是在psr0?include?path中進(jìn)行查找文件




本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開(kāi)發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開(kāi)幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉