php 如果类Map实际上更快,为什么要在composer中使用PSR-0或PSR-4自动加载呢?

ou6hu8tu  于 2023-02-11  发布在  PHP
关注(0)|答案(7)|浏览(172)

我知道你可以使用PSR标准来定位文件,或者告诉composer一个目录来扫描类。**文档推荐使用PSR-4标准。**composer还有一个选项来创建optimized autoloader, which basically generates a full classmap。那么,如果加载的最佳方式是使用类Map,为什么还要使用PSR-4呢?
对我来说,保留目录结构是有意义的,因为这是一种很好的组织方式。然而,似乎合理的选择是在开发机器上使用PSR-4加载,然后在生产环境中使用类Map。这样,您不必在每次创建新类时都重新构建类Map。但生产环境会创建一个完整的虚拟机,作为部署过程的一部分,而无需额外调用

./composer.phar dump-autoload -o
8tntrjer

8tntrjer1#

问题是类Map实际上并不是在所有情况下都更快!
类Map的速度来自于在加载文件、解析文件(操作码缓存在这里会有帮助)和执行文件之前,不必检查文件系统是否存在。
但是类Map的缺点是,你可能会为你所使用的库中包含的每一个类、接口和trait生成大量的数据,而你并没有在你的生产代码中实际使用它。加载巨大的数组不是免费的--同时代码也不需要一遍又一遍地解析(操作码缓存),它仍然必须被执行,数组数据结构必须被放入内存,用大量的字符串填充,然后消耗掉一些本来可以用于其他事情的内存。
我找到了两个讨论此主题的资源:首先,github issue #1529建议进一步改进composer autoloader,使用一堆符号链接来避免扫描多个目录。
这里的讨论也揭示了你应该在PSR-0 autoload声明中使用尽可能好的名称空间前缀或类名前缀,也就是尽可能长的前缀,你也可以在声明中使用多个前缀。
然后是a blog post linked in that issue,它记录了一些xhprof基准测试,使用了一个常用的EZPublish 5并修改了设置,包括APC缓存和类Map转储。
报价:
这个命令创建了一个662KiB的vendor/composer/autoload_classmap.php文件,其中包含一个数组,该数组是一个散列,由类名作为索引,包含类定义的文件的路径作为值组成。在我写这篇文章的时候,这个数组由4168个条目组成。[...]虽然它应该给我们提供最有效的自动加载机制,它实际上降低了速度(从254.53请求/秒降低到197.95),原因是即使文件由APC缓存,每次请求都需要重新创建包含4100个以上条目的Map的PHP数组。
类Map会很快吗?当然。在所有情况下都是最快的吗?当然不是--这取决于每个请求中使用的类与未使用的类的比率。因此,即使平均而言,您的应用程序实际上使用了Map中的所有类,如果每个请求中只使用了大约10%的类,那么类Map仍然可能会较慢,并且您最好优化所使用库的自动加载声明。实际上,每个类名前缀应该只指向一个目录。
请注意,您所获得的性能提升仅限于每个请求的低个位数毫秒。如果这个数字是5%到10%范围内的显著性能提升,那么您的应用程序肯定是非常棒的。但是如果您确实处于该性能范围内,那么盲目地相信类Map总是更快可能会浪费大量不必要的CPU周期。
如果您优化某项内容:测量它!如果你不能测量它,你怎么知道它是否真的变好了呢?

frebpwbc

frebpwbc2#

如果类Map实际上更快,为什么要在composer中使用PSR-0或PSR-4自动加载呢?
因为这样更实用。
在生产环境中,您可以使用classmap(带有composer dumpautoload -o),因为您不会添加任何新类,但在开发环境中,PSR-0或PSR-4提供的灵活性(即添加新类时无需执行任何操作)是很有趣的。

    • 更新:**您也可以使用composer install -o,它更简单。
qq24tv8q

qq24tv8q3#

如果您添加/更改了类,则需要执行以下操作:

***classmap:**composer转储加载(可能还需要使用新的classmap条目更新composer.json)
***psr-0:**无任何内容
***psr-4:**无结果

所以基本上你可以随意使用psr-4和psr-0而不用担心你新创建的类在autoloader中是否正确。2加上它你可以得到一个 free 正确的库目录结构,它代表你的命名空间。
自动加载器文件:

***类Map:**供应商/编译器/自动加载_类Map. php
***psr-0:**供应商/编写器/自动加载名称空间. php
***psr-4:**供应商/编写者/自动加载_psr4.php

pjngdqdw

pjngdqdw4#

这里一个重要的论点是,在composer.json中使用psr-4或psr-0会迫使你按照严格的标准来组织类文件,这会让其他人(或者2年后的你)看到composer.json时立即知道你的类在哪里。
如果你做错了,例如,如果你拼错了一个名称空间,那么你很可能会在开发或单元测试中发现,因为“类找不到”。这很好,因为它迫使你修复这个问题。
类Map要宽容得多,它允许任意组织类文件,让读者一无所知。
因此,正如其他人已经说过的那样:在composer.json中使用psr-4或psr-0,在开发过程中使用它,然后考虑在生产环境中使用-o选项,但是要衡量一下这是否真的带来了性能上的好处!

qyyhg6bp

qyyhg6bp5#

PSR-0和PSR-4(以及类Map)的问题是,它的实现没有考虑到优化,实现充其量是缺乏的。
然而,类Map背后的思想是有效的。
我创建了一个可以生成类Map的库,但是这个类Map更简单,而且经过了优化。
https://github.com/eftec/autoloadone
即使对于一个大的项目,Map也会减少,如果类包含在同一个文件夹中,它会将相同名称空间的相同类分组。如果不是,那么它们也会被包含在内。同样,如果类缺少名称空间,一个文件中有两个类,文件在范围之外,这也不是问题,它会跟踪所有类。你甚至可以排除一些文件夹或名称空间。
比如在一个大项目中

Number of Classes: 898
Number of Namespaces: 62
Number of Maps: 117
Number of PHP Files: 1693
Number of PHP Autorun: 0
Number of conflict: 1
Ratio map: 6.91% (less is better. 100% means one map/one file)
Map size: 12.9 kbytes (less is better, it's an estimate of the memory used by the map)

因此,对于一个包含898个类的项目,Map只使用了12.9kb。
性能有何不同:

  • 它不需要扫描文件夹(例如,如果文件不存在)。
  • 它不会验证文件是否不存在。
  • 它只是一个文件。因此,开销是一个include,而不是3个

Composer的自动加载包括(对于每次调用)以下文件:

  • autoload.php
  • composer/ClassLoader.php(取决于配置)
  • composer/autoload_real.php
  • composer/autoload_namespaces.php
  • composer/autoload_psr4.php
  • 配置文件/自动加载类Map. php(89 kb)

或者运行文件:

  • autoload.php
  • composer/ClassLoader.php(取决于配置)
  • 配置文件/自动加载_static. php(107 kb)

虽然Opcache确实令人惊叹,但我们仍然包括,至少,两个包括(而不是一个),加上其中一个是巨大的,它仍然是一个开销,它仍然是每个调用。
那么,哪个更快。这取决于项目,但我检查了通常PSR-0更快。然而,差异很小,两者都很慢。:-P

trnvg8h3

trnvg8h36#

概括起来,有两个概念:
1.建立文件Map,让composer知道要自动加载哪些文件。
1.为您的用例(开发与生产)生成最佳自动加载。
您可以使用PSR-0或PSR-4语法指定文件Map。

{
    "autoload": {
        "psr-4": {
            "Monolog\\": "src/",
            "Vendor\\Namespace\\": ""
        }
    }
}

参考:www.example.comhttps://getcomposer.org/doc/04-schema.md#autoload
使用以下选项之一指定所需的自动加载实现(对于级别1优化):

Set "optimize-autoloader": true inside the config key of composer.json
Call install or update with -o / --optimize-autoloader
Call dump-autoload with -o / --optimize

还有其他优化选项(参见文档)
参考:https://getcomposer.org/doc/articles/autoloader-optimization.md
优化选项将确定将生成何种类型的自动加载。任何优化都不会生成非常适合于开发目的的普通文件查找自动加载。其他优化将使用类Map,该类Map对于生产使用通常更快,但在每次创建、重命名或移动类时都需要重新生成。
这种混淆可能源于这样一个事实,即自动加载配置也接受类Map格式:

"autoload": {
        "classmap": ["src/addons/*/lib/", "3rd-party/*", "Something.php"]
    }

但医生明确表示:
您可以使用类Map生成支持为所有不遵循PSR-0/4的库定义自动加载。
关键词是"库",它通常变化缓慢。
如果您的代码没有Map到PSR-0/4,请为其创建自己的自动加载器。
您可以使用composer的自动加载功能为新代码生成一个自动加载器,并注册该自动加载器和您自己的自动加载器,从而过渡到PSR-4。

ulydmbyx

ulydmbyx7#

这个问题是误导性的。
"classmap"作为autoloading选项更准确地说只是一个哑目录glob,它引用了遇到的每个具有匹配名称的类的文件。然后,它将所有这些编译到"classmap数组"中,其中也有PSR-0规则。
因此,PSR-0和类Map使用相同的类Map,这意味着实际上没有区别。
使用PSR-0是因为您希望自动加载PSR-0代码。

相关问题