autoload php 原理,深刻理解composer的autoload自动加载原理

转载地址:http://www.toolmao.com/composer-autoloadphp

composer的出现真是让人们眼前一亮,web开发今后变成了一件很『好玩』的事情,开发一个CMS就像在搭积木,从packagist中取出『积木』搭建在本身的代码中,一点一点搭建出一个属于本身的王国。

今后之后我基本就抛弃了require和include函数,一个项目中,这两个函数只可能出现一次,那就是require '../vendor/autoload.php'。

那么,既然抛弃了传统的文件包含方法,咱们使用全部类库都将用namespace和composer自带的autoload。但是,咱们本身编写的函数库与类库,怎么用composer的方法来自动加载呢?web

这就要从composer.json提及,咱们须要经过修改这个文件来达到目的。

composer.json至关因而composer的配置文件,这个配置文件中有一个autoload段,好比个人一个项目:json

f2ed21eeccb043ec99b068b5.html

其中又包含主要的两个选项: files 和 psr-4。

files就是须要composer自动帮咱们加载的函数库(不含类),只要在后面的数组中将函数库的文件路径写入便可。

psr-4顾名思义,是一个基于psr-4(http://www.php-fig.org/psr/psr-4/)规则的类库自动加载对应关系,只要在其后的对象中,以 "命名空间": "路径" 的方式写入本身的类库信息便可。

修改完成后,只要执行一下composer update,便可完成对应工做。数组

以后,咱们在项目中,用以下方式便可加载自定义类库:composer

new\Core\View();

composer的autoload将会自动包含”./core/view.php”,并找到其中的Core命名空间下的View类。函数

咱们来深挖一下,探索一下autoload的原理。

在咱们修改完composer.json并执行update后,将会修改./vender/composer/autoload_psr4.php,好比个人某个项目,其中增长了这样一个对应关系:ui

f2ed21eeccb043ec99b068b5.html

这其实就是我刚刚在.json中添加的对应关系,他等于将.josn的配置文件,换成了php的形式。

那么我看到vendor/autoload.php:this

其执行了一个自动生成的类ComposerAutoloaderInitff1d77c91141523097b07ee2acc23326中的getLoader方法。

跟进:spa

publicstaticfunctiongetLoader(){if(null!==self::$loader){returnself::$loader;}spl_autoload_register(array('ComposerAutoloaderInitff1d77c91141523097b07ee2acc23326','loadClassLoader'),true,true);self::$loader=$loader=new\Composer\Autoload\ClassLoader();spl_autoload_unregister(array('ComposerAutoloaderInitff1d77c91141523097b07ee2acc23326','loadClassLoader'));$map=require__DIR__.'/autoload_namespaces.php';foreach($mapas$namespace=>$path){$loader->set($namespace,$path);}$map=require__DIR__.'/autoload_psr4.php';foreach($mapas$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($includeFilesas$file){composerRequireff1d77c91141523097b07ee2acc23326($file);}return$loader;}

能够明显看到,他将autoload_namespaces.php、autoload_psr4.php、autoload_classmap.php、autoload_files.php等几个配置文件包含了进来,并进行了相关处理(setPsr4),最后注册(register)。

那么咱们跟进register方法:.net

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

这函数就一行,但简单明了,直接调用php自带的spl_autoload_register函数,注册处理__autoload的方法,也就是loadClass方法。再跟进loadClass方法:

publicfunctionloadClass($class){if($file=$this->findFile($class)){includeFile($file);returntrue;}}

从函数名字就能够大概知道流程:若是存在$class对应的这个$file,则include进来。

那么进findFile方法里看看吧:

publicfunctionfindFile($class){// work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731if('\\'==$class[0]){$class=substr($class,1);}// class map lookupif(isset($this->classMap[$class])){return$this->classMap[$class];}if($this->classMapAuthoritative){returnfalse;}$file=$this->findFileWithExtension($class,'.php');// Search for Hack files if we are running on HHVMif($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;}

经过类名找文件,最终锁定在findFileWithExtension方法中。

不过发现了一个小宝藏:在php5.3.0~5.3.2版本下,类名的第一个字符是\的小bug,也许之后挖漏洞会用上。

仍是跟进findFileWithExtension方法:

privatefunctionfindFileWithExtension($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 dirsforeach($this->fallbackDirsPsr4as$dir){if(file_exists($file=$dir.DIRECTORY_SEPARATOR.$logicalPathPsr4)){return$file;}}// PSR-0 lookupif(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($dirsas$dir){if(file_exists($file=$dir.DIRECTORY_SEPARATOR.$logicalPathPsr0)){return$file;}}}}}// PSR-0 fallback dirsforeach($this->fallbackDirsPsr0as$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;}}

最终实现将命名空间\类这样的类名,给转换成目录名/类名.php这样的路径,并返回完整路径。

我发现composer的autoload与php自带的spl_autoload,在包含文件时有一点小区别。那就是,spl_autoload会查找.inc类型的文件名,但composer不会。

另外也能够发现,虽然配置文件的名字是autoload_psr4.php,但实际上psr0格式的自动加载也是支持的。两者最大的不一样就是psr0中用”_”来代替目录间的”\

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值