专栏首页沈唁志为什么Composer在生产环境要使用dumpautoload

为什么Composer在生产环境要使用dumpautoload

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 操作和深层次的循环,提升部分性能问题

沈唁志,一个PHPer的成长之路! 任何个人或团体,未经允许禁止转载本文:《为什么Composer在生产环境要使用dumpautoload》,谢谢合作!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 如何抓取猫眼电影Top100的影片信息?

    对于喜好电影的同学来说,猫眼电影和豆瓣电影应该是比较熟悉的电影评分的平台。但是,如何通过Python抓取猫眼电影评分前100的信息呢?

    测试小兵
  • 浏览器渗透之BeEF的高级烹饪方式

    Kali Linux内已经有BeEF的环境,只需要进入/usr/share/beef-xss目录下,./beef运行即可

    漏洞知识库
  • category在iOS开发中的使用

    上面是后端同学按照照module的方式开发的服务,在整个的项目中请求中前缀相同而每个module都有自己的前缀,结合起来整个请求URL格式就可以拆分为

    大话swift
  • linux+python+django基于django服务实现生成简易的二维码

    首先我简单的介绍下django;django官网解释就是如下:Django是一个开放源代码的Web应用框架,由Python写成。采用了MVC的框架模式,即模型M...

    测试小兵
  • 特别编辑--django项目关闭DEBUG开发模式无法访问静态资源解决方案

    django项目工程下的settings文件默认是将DEBUG模式开启的“DEBUG=Ture”方便调试当我们需要上线时此时我们则需关闭DEBUG模式因为项目中...

    测试小兵
  • 记一次有趣的一句话拿Shell的渗透测试过程

    拿到的是一个代理网站,简单先观察了下网站,发现使用的是PHP+ 宝塔 +Tp5框架的网站。通过弱口令进入后台任意文件上传拿shell。也不知道说啥,直接记录步骤...

    漏洞知识库
  • 一次早期自动化构建的搭建过程

    这是老王07年进入腾讯接手的第一个项目---自动化构建AutoBuild(06年就已经在上线运行),当年还不知道有Hudson,以及后来更名的Jenkins。做...

    用户1593318
  • liunx+python+django框架实现图片生成二维码

    Django是一个开放源代码的Web应用框架,由Python写成。采用了MVC的框架模式,即模型M,视图V和控制器C。它最初是被开发来用于管理劳伦斯出版集团旗下...

    测试小兵
  • 图片大小可控可导致CUP爆满造成网站瘫痪

    注意这个参数:size=200,可以看到下面服务器访问速度是76ms,图片是948B说明很快,那么我们把200改成10000

    漏洞知识库
  • CTF杂谈之PHP魔法与CBC加密

    PHP语言的开发者在几乎所有内置函数以及基本结构中使用了很多松散的比较和转换,防止程序中的变量因为程序员的不规范而频繁的报错,然而这却带来了安全问题。也正是因为...

    tinyfisher

扫码关注云+社区

领取腾讯云代金券