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

时间:2014-04-02 06:42:57

标签: php composer-php autoload psr-0 psr-4

据我所知,您可以使用PSR标准来查找文件,也可以告诉作曲家一个目录来扫描类。 documentation recommends using the PSR-4标准。作曲家还可以选择创建optimized autoloader, which basically generates a full classmap。那么,如果加载的最佳方法是使用类图,为什么要使用PSR-4呢?

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

./composer.phar dump-autoload -o

6 个答案:

答案 0 :(得分:45)

问题是,在每种情况下,类图实际上都不是更快!

类图的速度来自于在执行始终必要的加载工作之前不必检查文件系统,解析它(操作码缓存在这里会有帮助)然后执行它。

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

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

那里的讨论还表明,你应该尝试在PSR-0自动加载声明中使用最好的namespace-或classname-prefix,即最长的可能。您还可以在声明中使用多个前缀。

然后有a blog post linked in that issue使用股票EZPublish 5记录一些xhprof基准测试,并摆弄设置,包括APC缓存和类图转储。

钱报价:

  

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

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

请注意,您实现的性能增益仅在每个请求的低单位数毫秒范围内。如果这个数字在5到10%的范围内显着提升,那么你的应用肯定是非常棒的。但如果你真的处于这个性能范围内,盲目地认为类图总是更快可能会浪费很多不必要的CPU周期。

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

答案 1 :(得分:32)

  

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

因为它更实用。

在制作中,你可以使用一个类图(带有composer dumpautoload -o),因为你不会添加任何新的类,但在开发环境中,有趣的是具有PSR-0或PSR-4提供的灵活性(即添加新类时无事可做。)

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

答案 2 :(得分:10)

如果你添加/更改了课程,那么你需要做什么:

  • classmap: composer dumpautoload(也许还会使用新的classmap条目更新composer.json)
  • psr-0:没有
  • psr-4:没有

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

自动加载器文件:

  • classmap: vendor / composer / autoload_classmap.php
  • psr-0: vendor / composer / autoload_namespaces.php
  • psr-4: vendor / composer / autoload_psr4.php

答案 3 :(得分:2)

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

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

类图更宽容,并允许任意组织类文件,让读者处于黑暗中。

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

答案 4 :(得分:0)

PSR-0和PSR-4(以及类映射)的问题及其实现未考虑优化。充其量缺少实现。

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

我创建了一个可以生成类映射的库。但是,此类映射更为简单,但已进行了优化。

https://github.com/eftec/autoloadone

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

例如,在一个大项目中

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类的项目,地图仅使用12.9kb。

在性能上有什么区别

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

作曲家的自动加载功能(针对每个调用)包括以下文件:

  • autoload.php
  • composer / ClassLoader.php(取决于配置)
  • composer / autoload_real.php
  • composer / autoload_namespaces.php
  • composer / autoload_psr4.php
  • composer / autoload_classmap.php(89kb)

或运行文件:

  • autoload.php
  • composer / ClassLoader.php(取决于配置)
  • composer / autoload_static.php(107kb)

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

所以,这更快。这取决于项目,但我检查了通常PSR-0的速度是否更快。但是,差异很小,两者都很慢。 :-P

答案 5 :(得分:-1)

这个问题具有误导性。

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

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

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