为什么 require_once 不好用?

新手上路,请多包涵

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

为什么是这样?

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

原文由 Uberfuzzy 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 419
2 个回答

require_onceinclude_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

使用 require_once 慢 10-100 倍,奇怪的是 require_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.

原文由 Oli 发布,翻译遵循 CC BY-SA 3.0 许可协议

它没有使用不好的功能。在整个代码库中,这是对如何以及何时使用它的错误理解。我将为这个可能被误解的概念添加更多上下文:

人们不应该认为 require_once 是一个缓慢的函数。您必须以一种或另一种方式包含您的代码。 require_once()require() 的速度不是问题。这是关于性能阻碍可能导致盲目使用它的警告。如果在不考虑上下文的情况下广泛使用,可能会导致大量内存浪费或代码浪费。

我所看到的非常糟糕的是,当巨大的单体框架以所有错误的方式使用 require_once() 时,尤其是在复杂的面向对象 (OO) 环境中。

以在许多库中看到的每个类的顶部使用 require_once() 为例:

 require_once("includes/usergroups.php");
require_once("includes/permissions.php");
require_once("includes/revisions.php");
class User{
  // User functions
}

所以 User 类被设计为使用所有其他三个类。很公平!

但是现在,如果访问者正在浏览该站点并且甚至没有登录并且框架加载: require_once("includes/user.php"); 对于每个请求。

它包括在该特定请求期间永远不会使用的 1+3 个 不必要 的类。这就是臃肿的框架最终使用 40 MB 每个请求而不是 5 MB 或更少的原因。


它可能被滥用的其他方式是当一个类被许多其他人重用时!假设您有大约 50 个类使用 helper 函数。为了确保在加载这些类时 helpers 可用于这些类,您将获得:

 require_once("includes/helpers.php");
class MyClass{
  // Helper::functions(); // etc..
}

这里本身没有错。但是,如果一个页面请求恰好包含 15 个类似的类。您正在运行 require_once 15 次,或者为了获得漂亮的视觉效果:

 require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");
require_once("includes/helpers.php");

除了必须解析那些不必要的行之外,使用 require_once() 在技术上会影响运行该函数 14 次的性能。只有 10 个其他高度使用的类具有类似的问题,它可以解释 100 多行这种相当无意义的重复代码。

有了这个,在你的应用程序或框架的引导程序中使用 require("includes/helpers.php"); 可能是值得的。但由于一切都是相对的, 这完全取决于 helpers 类的重量与使用频率是否值得节省 require_once() 的 15-100 行。但是,如果在任何给定请求上不使用 helpers 文件的可能性为零,那么 require 绝对应该在您的主类中。在每个类中分别 require_once 会浪费资源。


require_once 函数在必要时很有用,但它不应被视为在任何地方用于加载所有类的单一解决方案。

原文由 hexalys 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题