为什么require_once使用起来这么糟糕?

2022-08-30 06:50:06

我读到的关于更好的PHP编码实践的所有内容都一直在说不要因为速度而使用。require_once

这是为什么呢?

做同样事情的正确/更好的方法是什么?如果这很重要,我正在使用PHP 5。require_once


答案 1

这个帖子让我畏缩,因为已经发布了一个“解决方案”,而且从所有意图和目的来看,它都是错误的。我们来列举:

  1. 定义在PHP中非常昂贵。您可以自己查找或测试它,但是在PHP中定义全局常量的唯一有效方法是通过扩展。(类常量实际上在性能方面相当不错,但这是一个有争议的问题,因为2)

  2. 如果您适当地使用,也就是说,为了包含类,您甚至不需要定义;只需检查是否.如果您包含的文件包含代码,即您以过程方式使用它,则绝对没有理由对您有必要;每次包含假定要进行子例程调用的文件时。require_once()class_exists('Classname')require_once()

所以有一段时间,很多人确实使用这种方法来制作他们的内含物。我不喜欢它,因为它很模糊,但他们有充分的理由:在一些更新版本的PHP之前效率非常低下。但这已经被修复了,我的论点是,你必须为条件和额外的方法调用编译的额外字节码远远超过任何内部哈希表检查。class_exists()require_once()

现在,承认:这些东西很难测试,因为它占执行时间太少了。

这是你应该考虑的问题:作为一般规则,include在PHP中是昂贵的,因为每次解释器命中一个,它必须切换回解析模式,生成操作码,然后跳回。如果您有 100 多个包含,这肯定会对性能产生影响。使用或不使用require_once是一个如此重要的问题,因为它使操作码缓存的生活变得困难。可以在这里找到对此的解释,但归根结底是:

  • 如果在解析期间,您确切地知道在请求的整个生命周期中需要哪些包含文件,那么在最开始和操作码缓存中将为您处理其他所有内容。require()

  • 如果您没有运行操作码缓存,那么您就处于困境。将所有包含的内容内联到一个文件中(不要在开发过程中执行此操作,只能在生产中执行此操作)当然可以帮助解析时间,但这样做很痛苦,而且,您需要确切地知道在请求期间将包含的内容。

  • 自动加载非常方便,但速度很慢,因为每次完成包含时都必须运行自动加载逻辑。在实践中,我发现为一个请求自动加载多个专用文件不会造成太大问题,但您不应该自动加载所需的所有文件。

  • 如果你有10个包含(这是一个非常背信封的计算),所有这些徘徊都不值得:只是优化你的数据库查询或其他东西。


答案 2

require_once并且两者都要求系统保留已包含/需要的内容的日志。每次调用都意味着检查该日志。所以肯定有一额外的工作在那里完成,但足以损害整个应用程序的速度?include_once*_once

...我真的怀疑它...除非您使用非常旧的硬件或经常这样做,否则不会。

如果你正在做成千上万的工作,你可以以更轻松的方式自己做这项工作。对于简单的应用程序,只需确保只包含一次就足够了,但是如果您仍然收到重新定义错误,则可以如下所示:*_once

if (!defined('MyIncludeName')) {
    require('MyIncludeName');
    define('MyIncludeName', 1);
}

我个人会坚持这些陈述,但在愚蠢的百万次通过基准测试上,你可以看到两者之间的区别:*_once

                php                  hhvm
if defined      0.18587779998779     0.046600103378296
require_once    1.2219581604004      3.2908599376678

10-100×慢,奇怪的是,在.同样,这仅在您运行数千次时才与您的代码相关。require_oncerequire_oncehhvm*_once


<?php // test.php

$LIMIT = 1000000;

$start = microtime(true);

for ($i=0; $i<$LIMIT; $i++)
    if (!defined('include.php')) {
        require('include.php');
        define('include.php', 1);
    }

$mid = microtime(true);

for ($i=0; $i<$LIMIT; $i++)
    require_once('include.php');

$end = microtime(true);

printf("if defined\t%s\nrequire_once\t%s\n", $mid-$start, $end-$mid);

<?php // include.php

// do nothing.

推荐