autoload之composer分析
来源:互联网 发布:tvp动画软件 编辑:程序博客网 时间:2024/06/06 00:18
这里要介绍的不是composer.phar,而且由php composer.phar install生成的整一个composer文件下的autoload的结构。
想在项目总引入composer进行包管理,都会说将需要的包填到composer.json文件,然后执行composer install,会在vender文件夹下生成autoload.php,项目中引入这个文件就可以实现类的自动加载了。
那引入autoload.php之后到底做了帮我们做了什么,我们一起来看看。
首先查看autoload.php:
<?php// autoload.php @generated by Composerrequire_once __DIR__ . '/composer' . '/autoload_real.php';return ComposerAutoloaderInit621850f9ac0e7f3f7c90ee4affc93eee::getLoader();
这里是require了一个compsoer/autoload_real.php文件,然后返回了一个getLoader()静态方法,看来我们要进去这个方法里看一下。
(ps: autoload_real.php 这个名字中也能看出,这才是真正实现autoload机制的地方)
<?php// autoload_real.php @generated by Composerclass ComposerAutoloaderInit621850f9ac0e7f3f7c90ee4affc93eee{ private static $loader; public static function loadClassLoader($class) { if ('Composer\Autoload\ClassLoader' === $class) { require __DIR__ . '/ClassLoader.php'; } } public static function getLoader() { //如果成员$loader已经赋值就直接返回,典型的单例模式 if (null !== self::$loader) { return self::$loader; } //将ComposerAutoloaderInit621850f9ac0e7f3f7c90ee4affc93eee类中的loadClassLoader方法注册为自动类加载处理函数 spl_autoload_register(array('ComposerAutoloaderInit621850f9ac0e7f3f7c90ee4affc93eee', 'loadClassLoader'), true, true); //使用新注册的loadClassLoader方法加载\Composer\Autoload\ClassLoader类,并实例化一个对象 self::$loader = $loader = new \Composer\Autoload\ClassLoader(); //注销loadClassLoader spl_autoload_unregister(array('ComposerAutoloaderInit621850f9ac0e7f3f7c90ee4affc93eee', 'loadClassLoader')); //如果php版本大于5.6并且未定义HHVM_VERSION常量,返回true $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION'); if ($useStaticLoader) { //autoload_static.php 记录了namespace+类名与类所在文件的映射关系 require_once __DIR__ . '/autoload_static.php'; //降映射关系加载到$loader里 call_user_func(\Composer\Autoload\ComposerStaticInit621850f9ac0e7f3f7c90ee4affc93eee::getInitializer($loader)); } else { //设置单独namespace对于的文件夹位置的映射关系 $map = require __DIR__ . '/autoload_namespaces.php'; foreach ($map as $namespace => $path) { $loader->set($namespace, $path); } //符合psr4命名规范的namespace对于的文件夹位置的映射关系 $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); //需要预先require的文件 if ($useStaticLoader) { $includeFiles = Composer\Autoload\ComposerStaticInit621850f9ac0e7f3f7c90ee4affc93eee::$files; } else { $includeFiles = require __DIR__ . '/autoload_files.php'; } foreach ($includeFiles as $fileIdentifier => $file) { composerRequire621850f9ac0e7f3f7c90ee4affc93eee($fileIdentifier, $file); } return $loader; }}function composerRequire621850f9ac0e7f3f7c90ee4affc93eee($fileIdentifier, $file){ //循环导入文件,并记录到$GLOBALS['__composer_autoload_files']变量中 if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { require $file; $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; }}
到这里,对autoload的初始化就完成了,接下来是对一个类的查找工作。
在composer/ClassLoader.php
public function register($prepend = false) { spl_autoload_register(array($this, 'loadClass'), true, $prepend); }使用本类中的loadClass()方法来处理未找到的类:
public function loadClass($class) { if ($file = $this->findFile($class)) { includeFile($file); return true; } }这方法就是先查找该类是否存在,存在则include进来。再看看findFile()方法是如何查找并返回类的:
/** * 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) { // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731 //如果类名以\开头,则从第二字符开始截取类名 if ('\\' == $class[0]) { $class = substr($class, 1); } // class map lookup //在$this->classMap中查找$class,找到就返回文件名 if (isset($this->classMap[$class])) { return $this->classMap[$class]; } //是否有权利访问classMap if ($this->classMapAuthoritative) { return false; } //上面没匹配到,这里再匹配 $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]; //prefixLengthsPsr4中根据首字母进行了分类,可查看autoload_static.php中的prefixLengthsPsr4成员变量 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 //自定义的psr4规则 foreach ($this->fallbackDirsPsr4 as $dir) { if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { return $file; } } // PSR-0 lookup //如果是符合psr0规则的,则替换_为/ 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; } //prefixesPsr0中根据首字母进行了分类,可查看autoload_static.php中的prefixesPsr0成员变量 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 //用户添加符合psr0的规则 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; } }
顺序是先查classMap,因为大部分类的映射关系都在这个变量里,然后下面findFileWithExtension()方法里是以一些其他维度进行查询。
整体class的autoload的init和find就是这样,好像主要的工作还是在php composer.phar install的时候已经完成了,这个时候就已经理出了类名和类所在文件的映射关系。
0 0
- autoload之composer分析
- composer autoload
- composer autoload原理浅析
- 深入 Composer autoload
- 深入 Composer autoload
- 深入理解Composer autoload
- Yii2与Composer中的autoload
- 【php】 勾搭 Composer\Autoload\ClassLoader 类
- php composer autoload添加个性化命名空间
- PHP autoload性能分析
- ActiveSupport autoload源码分析
- What does ‘composer dump-autoload’ do in Laravel?
- 深入理解composer的autoload自动加载原理
- php之自动加载autoload
- 云客Drupal8源码分析之自动加载器与Composer
- Composer源码分析
- PHP管理依赖(dependency)关系工具 Composer的自动加载(autoload)
- 如何使用composer的autoload来自动加载自己编写的函数库与类库
- mybatis的查询类型
- Red Hat Enterprise 6.5 在虚拟机上将系统语言修改为中文
- HDU 5649 (二分 线段树)
- 关于 ZJCPC2004第二题
- Java VisualVM 多线程监控分析工具
- autoload之composer分析
- 我的第一次vi经历
- 详解Java中native关键字
- HDU 1711 Number Sequence【数字KMP】
- 统一会话
- php单例模式
- hdu 1285 拓扑排序
- 服务器开发之图形验证码
- Windows程序内部运行原理