欢迎各位兄弟 发布技术文章
这里的技术是共享的
这篇文章来说一下为什么在生产环境下使用 Composer 加载包后要再使用 dumpautoload 呢?
composer dump-autoload (-o) composer dumpautoload (-o)
这个就要看一下 vendor/composer 目录下的文件了,先看一下 autoload_real.php
类名为 ComposerAutoloaderInit440563a888dcb3a8c02b3ef8400e84e8,ComposerAutoloaderInit 后为一段 hash 值
这个也是为了避免命名冲突,每次 composer install 都会生成不一样的值
再往下看 getLoader 这个方法
public static function getLoader() { if (null !== self::$loader) { return self::$loader; } spl_autoload_register(array('ComposerAutoloaderInit440563a888dcb3a8c02b3ef8400e84e8', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(); spl_autoload_unregister(array('ComposerAutoloaderInit440563a888dcb3a8c02b3ef8400e84e8', '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\ComposerStaticInit440563a888dcb3a8c02b3ef8400e84e8::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); return $loader; }
这个方法是获取 Composer\ClassLoader,如果不存在就是生成一个实例放在 ComposerAutoloaderInit440563a888dcb3a8c02b3ef8400e84e8 中
将 Composer 生成的各种 autoload_psr4、autoload_classmap、autoload_namespaces 全都注册到 Composer\ClassLoader 中
然后 register 注册文件
了解了 autoload.php 是如何工作的,以后那么我们看一下composer dump-atoload -o
有什么用
autoload_classmap.php 在未执行命名之前 return 了一个空数组
在执行之后会发现所有的扩展包类的 namespace 和 classname 生成成一个 key => value 的数组
这时我们需要分析一下 ClassLoader 这个类的源码
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; }
我们可以看到会先去查找 autoload_classmap 中所有生成的注册类,如果没有才会加载 psr-4 和 psr-0
所以使用 dumpautoload 后会优先加载需要的类并提前返回,不然的话 compoesr 只能去动态读取 psr-4 和 prs-0 的内容,这样大大减少了 IO 操作和深层次的循环,提升部分性能问题
来自 https://cloud.tencent.com/developer/article/1550789