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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22803419/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 16:16:34  来源:igfitidea点击:

Why use a PSR-0 or PSR-4 autoload in composer if classmap is actually faster?

phpcomposer-phpautoloadpsr-0psr-4

提问by Bryan Agee

I understand that you can use either a PSR standard to locate files, or tell composer a directory to scan for classes. The documentation recommends using the PSR-4standard.There is also an option for composer to create an optimized autoloader, which basically generates a full classmap. So why should one use PSR-4 at all if the best way to load is with a classmap?

我知道您可以使用 PSR 标准来定位文件,或者告诉作曲家一个目录来扫描类。文档建议使用 PSR-4标准。作曲家还有一个选项可以创建一个优化的自动加载器,它基本上生成一个完整的 classmap。那么,如果加载类图的最佳方式是使用 PSR-4,那为什么还要使用 PSR-4?

It makes sense to me to keep the directory structure, since that is a good way to organize anyway. However, it seems like the logical option would be to use PSR-4 loading on development machines, and then classmap for the production environment. That way, you don't have to rebuild your classmap every time you create a new class, but the production environment creates a complete one as a part of the deployment process without an additional call to

保留目录结构对我来说很有意义,因为无论如何这是一种很好的组织方式。但是,似乎合乎逻辑的选择是在开发机器上使用 PSR-4 加载,然后在生产环境中使用类映射。这样,您不必每次创建新类时都重新构建类映射,但生产环境会在部署过程中创建一个完整的类映射,而无需额外调用

./composer.phar dump-autoload -o

回答by Sven

The problem is that the classmap is NOT actually faster in every case!

问题是 classmap 实际上并不是在每种情况下都更快!

The speed of the classmap comes from not having to check the filesystem if a file exists before doing the always necessary work of loading it, parsing it (opcode caches will help here) and then executing it.

classmap 的速度来自于在执行加载文件、解析它(操作码缓存在这里会有所帮助)然后执行它的总是必要的工作之前不必检查文件系统是否存在文件。

But the downside of the classmap is that you possibly generate a huge amount of data for every single class, interface and trait included in the libraries you use, without you actually using it in your production code. Loading huge arrays does not come for free - while the code need not be parsed again and again (opcode cache), it still has to be executed, the array data structure has to be put into memory, filled with lots of strings, and then eats up some amount of memory that might have been usable for something else.

但是 classmap 的缺点是您可能会为您使用的库中包含的每个类、接口和特征生成大量数据,而您实际上并未在生产代码中使用它。加载庞大的数组不是免费的——虽然代码不需要反复解析(操作码缓存),但它仍然必须执行,数组数据结构必须放入内存,填充大量字符串,然后占用了一些可能可用于其他用途的内存。

I found two resources discussing this topic: First of all there is github issue #1529suggesting further improvements for the composer autoloader using a bunch of symlinks to avoid having to scan multiple directories.

我找到了两个讨论这个主题的资源:首先,github 问题 #1529建议使用一堆符号链接对作曲家自动加载器进行进一步改进,以避免扫描多个目录。

The discussion there also reveals that you should actually try to use the best possible namespace- or classname-prefix in the PSR-0 autoload declaration, i.e. the longest one possible. You can also use more than one prefix in the declaration.

那里的讨论还表明,您实际上应该尝试在 PSR-0 自动加载声明中使用尽可能最好的命名空间或类名前缀,即尽可能长的前缀。您还可以在声明中使用多个前缀。

Then there is a blog post linked in that issuethat documents some xhprof benchmarks using a stock EZPublish 5 and fiddling with the settings, including APC Caching and classmap dumping.

然后在该问题链接了一篇博客文章,其中记录了一些使用股票 EZPublish 5 和摆弄设置(包括 APC 缓存和类映射转储)的 xhprof 基准测试。

Money quote:

金钱报价:

This command created a 662KiB vendor/composer/autoload_classmap.php file containing an array that is a hash composed of the class name as index and the path to the file containing the class definition as value. At the time I am writing this post, this array is composed of 4168 entries. [...] Although it should give us the most efficiant autoloading mechanism, it actually slows things down (from 254.53 reqs/second to 197.95). The reason being that even if the file is cached by APC, the PHP array containing the map with more than 4100 entries needs to be re-created at every single request.

此命令创建了一个 662KiB 的 vendor/composer/autoload_classmap.php 文件,该文件包含一个数组,该数组是由类名作为索引和包含类定义的文件的路径作为值组成的散列。在我写这篇文章的时候,这个数组由 4168 个条目组成。[...] 虽然它应该给我们最有效的自动加载机制,但它实际上减慢了速度(从 254.53 请求/秒到 197.95)。原因是即使文件被 APC 缓存,包含超过 4100 个条目的映射的 PHP 数组也需要在每次请求时重新创建。

Will a classmap be fast? Certainly. Fastest in every case? Of course not - it depends on the ratio used vs. unused classes per request. So even if on average your application actually uses ALL classes in the map, a classmap might still be slower if you only use about 10% of the classes per request, and you'd be better off optimizing the autoload declarations of the libraries you use. In fact, every classname prefix should only ever point to exactly one directory.

类图会很快吗?当然。在每种情况下都是最快的?当然不是 - 这取决于每个请求使用的类与未使用的类的比率。因此,即使平均而言您的应用程序实际上使用映射中的所有类,如果您每个请求只使用大约 10% 的类,类映射可能仍然会更慢,并且您最好优化您使用的库的自动加载声明. 事实上,每个类名前缀都应该只指向一个目录。

Note that the performance gain you'd achieve only is in the area of about low single digit milliseconds per request. Your application surely is awesome if that figure is a significant performance boost in the range of 5 to 10%. But if you really are in that performance range, blindly believing that a classmap is ALWAYS faster probably wastes a lot of unnecessary CPU cycles.

请注意,您获得的性能提升仅在每个请求大约低个位数毫秒的范围内。如果该数字是 5 到 10% 范围内的显着性能提升,那么您的应用程序肯定很棒。但是如果你真的在那个性能范围内,盲目地相信类映射总是更快可能会浪费很多不必要的 CPU 周期。

If you optimize something: Measure it! How would you know if it actually becomes better if you cannot measure it?

如果你优化了一些东西:衡量它!如果你无法衡量它,你怎么知道它是否真的变得更好?

回答by Matthieu Napoli

Why use a PSR-0 or PSR-4 autoload in composer if classmap is actually faster?

如果 classmap 实际上更快,为什么要在 Composer 中使用 PSR-0 或 PSR-4 自动加载?

Because it's more practical.

因为它更实用。

In production, you can use a classmap (with composer dumpautoload -o) because you won't add any new class, but in dev environment it's interesting to have the flexibility provided by PSR-0 or PSR-4 (i.e. nothing to do when adding new classes).

在生产中,您可以使用 classmap (with composer dumpautoload -o),因为您不会添加任何新类,但在开发环境中,拥有 PSR-0 或 PSR-4 提供的灵活性很有趣(即添加新类时无需执行任何操作) .

Update:you can also use composer install -o, it's simpler.

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

回答by zwacky

here's what you'd need to do, if you added/changed classes:

如果您添加/更改了类,这就是您需要做的事情:

  • classmap:composer dumpautoload (perhaps also update composer.json with a new classmap entry)
  • psr-0:nothing
  • psr-4:nothing
  • classmap:composer dumpautoload(也许还使用新的 classmap 条目更新 composer.json)
  • psr-0:没有
  • psr-4:没什么

so basically you can go wild with psr-4 and psr-0 without having to worry, whether your newly created class is correctly in the autoloader. plus with it you get a freeproper directory structure of your library, that represents your namespace.

所以基本上你可以随意使用 psr-4 和 psr-0 而不必担心你新创建的类是否在自动加载器中正确。加上它,您可以获得库的免费正确目录结构,它代表您的命名空间。

autoloader files:

自动加载文件:

  • classmap:vendor/composer/autoload_classmap.php
  • psr-0:vendor/composer/autoload_namespaces.php
  • psr-4:vendor/composer/autoload_psr4.php
  • 类图:供应商/作曲家/autoload_classmap.php
  • psr-0:供应商/作曲家/autoload_namespaces.php
  • psr-4:供应商/作曲家/autoload_psr4.php

回答by donquixote

An important argument here is that using psr-4 or psr-0 in the composer.json forcesyou to organize your class files following a strict standard. This allows others (or yourself 2 years from now) who look at the composer.json to immediately know where your classes are.

这里的一个重要论点是,在 composer.json 中使用 psr-4 或 psr-0 会强制您按照严格的标准组织类文件。这允许查看 composer.json 的其他人(或 2 年后的您自己)立即知道您的类在哪里。

If you do this wrong, e.g. if you misspell a namespace, then you will likely find out during development or in your unit tests due to a "class not found". This is good, because it forces you to fix this.

如果你做错了,例如,如果你拼错了一个命名空间,那么你很可能会在开发或单元测试中发现由于“找不到类”。这很好,因为它迫使你解决这个问题。

The classmap is much more forgiving, and will allow any arbitrary organization of class files, leaving the reader in the dark.

classmap 更宽容,允许任意组织 class 文件,让读者一无所知。

So, as others already said: Use psr-4 or psr-0 in the composer.json, work with that during development, and then consider the -o option for production. But measure if this really brings a performance benefit!

所以,正如其他人已经说过的:在 composer.json 中使用 psr-4 或 psr-0,在开发过程中使用它,然后在生产中考虑 -o 选项。但是衡量这是否真的带来了性能优势!

回答by magallanes

The problem with PSR-0 and PSR-4 (and the class-map) its implementation doesn't consider the optimization. The implementation is lacking at best.

PSR-0 和 PSR-4(以及类映射)的问题,它的实现没有考虑优化。充其量缺乏实施。

However, the idea behind the class-map works.

然而,类映射背后的想法是有效的。

I created a library that works generating a class-map. However, this class-map is way simpler yet it's optimized.

我创建了一个可以生成类映射的库。然而,这个类映射更简单,但它已经过优化。

https://github.com/eftec/autoloadone

https://github.com/eftec/autoloadone

The map is reduced even for a big project, it groups the same classes of the same namespace if they are contained in the same folder. If not, then it's not a problem they are also included. Also, if the class lack of namespace, two classes in a file, the file is outside of the scope, it's not a problem, it tracks all of them. You could even exclude some folders or namespace.

即使对于一个大项目,映射也会减少,如果它们包含在同一文件夹中,它会将同一命名空间的相同类分组。如果没有,那么它们也包括在内不是问题。另外,如果类缺少命名空间,一个文件中有两个类,文件在范围之外,这不是问题,它会跟踪所有这些。您甚至可以排除某些文件夹或命名空间。

For example, in a big project

例如,在一个大项目中

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)

So, for a project with 898 classes, the map uses only 12.9kb.

因此,对于具有 898 个类的项目,地图仅使用 12.9kb。

And what's the difference in performance:

性能上有什么不同:

  • it doesn't need to scan a folder (for example if the file doesn't exist).
  • it doesn't verify if the file doesn't exist.
  • it's only a single file. So, the overhead is a single include, not 3 for
  • 它不需要扫描文件夹(例如,如果文件不存在)。
  • 它不会验证文件是否不存在。
  • 它只是一个文件。因此,开销是单个包含,而不是 3 个

Composer's autoload includes (for each call) the next files:

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

  • autoload.php
  • composer/ClassLoader.php (it depends in the configuration)
  • composer/autoload_real.php
  • composer/autoload_namespaces.php
  • composer/autoload_psr4.php
  • composer/autoload_classmap.php (89kb)
  • 自动加载.php
  • composer/ClassLoader.php (取决于配置)
  • 作曲家/autoload_real.php
  • 作曲家/autoload_namespaces.php
  • 作曲家/autoload_psr4.php
  • composer/autoload_classmap.php (89kb)

or it runs the files:

或者它运行文件:

  • autoload.php
  • composer/ClassLoader.php (it depends in the configuration)
  • composer/autoload_static.php (107kb)
  • 自动加载.php
  • composer/ClassLoader.php (取决于配置)
  • composer/autoload_static.php (107kb)

While Opcache does marvel but we are still including, at least, two includes (instead of one), plus one of them is huge and it is still an overhead, and it is still per call.

虽然 Opcache 确实令人惊叹,但我们仍然至少包含两个包含(而不是一个),加上其中一个很大并且仍然是开销,并且仍然是每次调用。

So, which is faster. It depends on the project but I checked that usually PSR-0 is faster. However, the difference is dim, both are slow. :-P

所以,哪个更快。这取决于项目,但我检查过通常 PSR-0 更快。然而,差异是微弱的,两者都是缓慢的。:-P

回答by Phil Sturgeon

The question is misleading.

这个问题具有误导性。

"classmap" as the autoloading option is more accurately just a dumb directory glob with a reference to every file it comes across that has a class with a matching name. It then compiles all of that into the "classmap array", which ALSO has PSR-0 rules in there.

“classmap”作为自动加载选项更准确地说只是一个愚蠢的目录glob,引用它遇到的每个具有匹配名称的类的文件。然后它将所有这些编译到“类映射数组”中,其中也有 PSR-0 规则。

So, PSR-0 and classmap use the same classmap, meaning there is literally no difference.

因此,PSR-0 和 classmap 使用相同的 classmap,这意味着实际上没有区别。

You use PSR-0 because you want to autoload PSR-0 code.

您使用 PSR-0 是因为您想自动加载 PSR-0 代码。