Composer作为现代phper的春天,远离重复造轮子的时代,大部分扩展包遵循psr-4规范,使得扩展更加轻松,减轻了工作的部分压力
这篇文章来说一下为什么在生产环境下使用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操作和深层次的循环,提升部分性能问题
厉害啊,小老弟