当前位置:首页 > CMS教程 > 其它CMS > 列表

分析Composer实现自动加载原理

发布:smiling 来源: PHP粉丝网  添加日期:2022-05-02 10:40:58 浏览: 评论:0 

一般在框架中都会用到composer工具, 用它来管理依赖。其中 composer有类的自动加载机制,可以加载composer下载的库中的所有的类文件。那么composer的自动加载机制是怎么实现的呢?

1. 入口文件

(/public/index.php)中引入了 autoload.php

require __DIR__.'/../vendor/autoload.php';<br data-filtered="filtered">

2.  autoload.php

  1. require_once __DIR__ . '/composer/autoload_real.php'
  2.  
  3. return ComposerAutoloaderInit1215780529014c2b50a6fca7ce889273::getLoader();<br data-filtered="filtered"

3. autoload_real.php

  1. <?php 
  2. // autoload_real.php @generated by Composer 
  3. class ComposerAutoloaderInit1215780529014c2b50a6fca7ce889273{ 
  4.     private static $loader
  5.     public static function loadClassLoader($class){ 
  6.         if ('Composer\Autoload\ClassLoader' === $class) { 
  7.             require __DIR__ . '/ClassLoader.php'
  8.         } 
  9.     } 
  10.     public static function getLoader(){ 
  11.         if (null !== self::$loader) { 
  12.             return self::$loader
  13.         } 
  14.         spl_autoload_register(array('ComposerAutoloaderInit1215780529014c2b50a6fca7ce889273''loadClassLoader'), true, true); 
  15.         self::$loader = $loader = new \Composer\Autoload\ClassLoader(); 
  16.         spl_autoload_unregister(array('ComposerAutoloaderInit1215780529014c2b50a6fca7ce889273''loadClassLoader')); 
  17.         $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); 
  18.         if ($useStaticLoader) { 
  19.             require_once __DIR__ . '/autoload_static.php'
  20.    
  21.             call_user_func(\Composer\Autoload\ComposerStaticInit1215780529014c2b50a6fca7ce889273::getInitializer($loader)); 
  22.         } else { 
  23.             $map = require __DIR__ . '/autoload_namespaces.php'
  24.             foreach ($map as $namespace => $path) { 
  25.                 $loader->set($namespace$path); 
  26.             } 
  27.             $map = require __DIR__ . '/autoload_psr4.php'
  28.             foreach ($map as $namespace => $path) { 
  29.                 $loader->setPsr4($namespace$path); 
  30.             } 
  31.             $classMap = require __DIR__ . '/autoload_classmap.php'
  32.             if ($classMap) { 
  33.                 $loader->addClassMap($classMap); 
  34.             } 
  35.         } 
  36.         $loader->register(true); 
  37.         if ($useStaticLoader) { 
  38.             $includeFiles = Composer\Autoload\ComposerStaticInit1215780529014c2b50a6fca7ce889273::$files
  39.         } else { 
  40.             $includeFiles = require __DIR__ . '/autoload_files.php'
  41.         } 
  42.         foreach ($includeFiles as $fileIdentifier => $file) { 
  43.             composerRequire1215780529014c2b50a6fca7ce889273($fileIdentifier$file); 
  44.         } 
  45.    
  46.         return $loader
  47.     } 
  48. function composerRequire1215780529014c2b50a6fca7ce889273($fileIdentifier$file){ 
  49.     if (emptyempty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { 
  50.         require $file
  51.    
  52.         $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; 
  53.     } 

可以看出这一段是 composer 自动加载的重点,首先在 autoload.php 中调用

ComposerAutoloaderInit1215780529014c2b50a6fca7ce889273::getLoader () 方法,getLoader () 首先判断当前loader是不是null,如果不为null就直接返回,否则就初始化一个ClassLoader类给赋值给 loader 是不是 null,如果不为 null 就直接返回,否则就初始化一个 ClassLoader 类给赋值给 loader,接着将 autoload_namespaces.php、autoload_psr4.php、autoload_classmap.php 文件中的内容加入到 $loader 中对应的数组中,然后给注册 loadClass 函数,将 autoload_files.php 中的所有路径所示的文件都包含进来,当在 new 一个类的时候如果没有找到相关的类就会触发这个 loadClass 函数,在 loadClass () 又调用了 findFile () 去查找相应的文件,找到相应文件后就会返回该文件,然后 loadClass 调用 includeFile () 方法将该文件 include 进去,否则 findFile 返回 false,这样就完成了自动加载

4.  findFile ()

  1. public function findFile($class){ 
  2.     // class map lookup 
  3.     if (isset($this->classMap[$class])) { 
  4.         return $this->classMap[$class]; 
  5.     } 
  6.     if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { 
  7.         return false; 
  8.     } 
  9.     if (null !== $this->apcuPrefix) { 
  10.         $file = apcu_fetch($this->apcuPrefix.$class$hit); 
  11.         if ($hit) { 
  12.             return $file
  13.         } 
  14.     } 
  15.     $file = $this->findFileWithExtension($class'.php'); 
  16.     // Search for Hack files if we are running on HHVM 
  17.     if (false === $file && defined('HHVM_VERSION')) { 
  18.         $file = $this->findFileWithExtension($class'.hh'); 
  19.     } 
  20.     if (null !== $this->apcuPrefix) { 
  21.         apcu_add($this->apcuPrefix.$class$file); 
  22.     } 
  23.     if (false === $file) { 
  24.         // Remember that this class does not exist. 
  25.         $this->missingClasses[$class] = true; 
  26.     } 
  27.     return $file
  28.  
  29. private function findFileWithExtension($class$ext){ 
  30.     // PSR-4 lookup 
  31.     $logicalPathPsr4 = strtr($class'\\', DIRECTORY_SEPARATOR) . $ext
  32.  
  33.     $first = $class[0]; 
  34.     if (isset($this->prefixLengthsPsr4[$first])) { 
  35.         $subPath = $class
  36.         while (false !== $lastPos = strrpos($subPath'\\')) { 
  37.             $subPath = substr($subPath, 0, $lastPos); 
  38.             $search = $subPath.'\\'
  39.             if (isset($this->prefixDirsPsr4[$search])) { 
  40.                 $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4$lastPos + 1); 
  41.                 foreach ($this->prefixDirsPsr4[$searchas $dir) { 
  42.                     if (file_exists($file = $dir . $pathEnd)) { 
  43.                         return $file
  44.                     } 
  45.                 } 
  46.             } 
  47.         } 
  48.     } 
  49.     // PSR-4 fallback dirs 
  50.     foreach ($this->fallbackDirsPsr4 as $dir) { 
  51.         if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { 
  52.             return $file
  53.         } 
  54.     } 
  55.  
  56.     // PSR-0 lookup 
  57.     if (false !== $pos = strrpos($class'\\')) { 
  58.         // namespaced class name 
  59.         $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) 
  60.         . strtr(substr($logicalPathPsr4$pos + 1), '_', DIRECTORY_SEPARATOR); 
  61.     } else { 
  62.         // PEAR-like class name 
  63.         $logicalPathPsr0 = strtr($class'_', DIRECTORY_SEPARATOR) . $ext
  64.     } 
  65.  
  66.     if (isset($this->prefixesPsr0[$first])) { 
  67.         foreach ($this->prefixesPsr0[$firstas $prefix => $dirs) { 
  68.             if (0 === strpos($class$prefix)) { 
  69.                 foreach ($dirs as $dir) { 
  70.                     if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { 
  71.                         return $file
  72.                     } 
  73.                 } 
  74.             } 
  75.         } 
  76.     } 
  77.  
  78.     // PSR-0 fallback dirs 
  79.     foreach ($this->fallbackDirsPsr0 as $dir) { 
  80.         if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { 
  81.             return $file
  82.         } 
  83.     } 
  84.     // PSR-0 include paths. 
  85.     if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { 
  86.         return $file
  87.     } 
  88.     return false; 

findFile () 函数先在 classMap 中查找,如果找不到的话就会尝试在 apcu 缓存中查找,如果还是找不到的话就会调用 findFileWithExtension () 函数查找,如果找到了就会将该文件加到apcu缓存,如果找不到的话就会在 missingClasses 数组中设一个标记表示识这个类找不到findFileWithExtension()方法根据之前通过loader->set(loader−>set(namespace, path)和path)和loader->setPsr4(namespace,namespace,path)方法设置的信息找出类文件的路径信息

5. spl_autoload_register和spl_autoload_unregister函数

1. spl_autoload_register 函数

1.spl_autoload_register — 注册给定的函数作为 __autoload 的实现,

bool spl_autoload_register([callable autoloadfunction[,boolautoloadfunction[,boolthrow = true [, bool $prepend = false ]]])

2.prepend

如果是 true,spl_autoload_register () 会添加函数到队列之首,而不是队列尾部。

3.如果在你的程序中已经实现了 autoload () 函数,它必须显式注册到 autoload () 队列中。因为 spl_autoload_register () 函数会将 Zend Engine 中的__autoload () 函数取代为 spl_autoload () 或 spl_autoload_call ()

例:function __autoload($name) { require 'class/'.$name.'.php'; echo '1'; } function autoload_test($name) { echo '2'; } spl_autoload_register('autoload_test'); spl_autoload_register('__autoload'); $ca=new Ca();

2. spl_autoload_unregister 函数

spl_autoload_unregister — 注销已注册的 autoload () 函数,如果该函数队列处于激活状态,并且在给定函数注销后该队列变为空,则该函数队列将会变为无效。如果该函数注销后使得自动装载函数队列无效,即使存在有 autoload 函数它也不会自动激活。

bool spl_autoload_unregister ( mixed $autoload_function )

Tags: Composer

分享到: