30

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

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

./composer.phar dump-autoload -o
4

6 回答 6

50

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

类映射的速度来自于在执行加载文件、解析文件(操作码缓存将在此处提供帮助)然后执行它之前,不必检查文件系统是否存在。

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

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

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

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

金钱报价:

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

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

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

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

于 2014-04-02T22:03:27.480 回答
34

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

因为它更实用。

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

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

于 2014-04-02T09:33:03.087 回答
11

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

  • 类映射: composer dumpautoload(也许还使用新的类映射条目更新 composer.json)
  • psr-0:什么都没有
  • psr-4:什么都没有

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

自动加载器文件:

  • 类图:供应商/作曲家/autoload_classmap.php
  • psr-0:供应商/作曲家/autoload_namespaces.php
  • psr-4:供应商/作曲家/autoload_psr4.php
于 2014-04-02T07:07:36.163 回答
2

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

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

类图更加宽容,允许任意组织类文件,让读者一头雾水。

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

于 2014-09-20T14:04:17.197 回答
1

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 个

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

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

或者它运行文件:

  • 自动加载.php
  • composer/ClassLoader.php(取决于配置)
  • 作曲家/autoload_static.php (107kb)

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

所以,哪个更快。这取决于项目,但我检查过 PSR-0 通常更快。但是,区别很微弱,两者都很慢。:-P

于 2018-10-31T00:15:42.540 回答
-1

这个问题具有误导性。

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

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

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

于 2014-04-03T08:12:14.853 回答