为什么require_once使用起来如此糟糕?

时间:2023-02-08 13:57:40

Everything I read about better PHP coding practices keeps saying don't use require_once because of speed.

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

Why is this?

这是为什么呢?

What is the proper/better way to do the same thing as require_once? If it matters, I'm using PHP5.

做和require_once一样的事情的正确/更好的方法是什么?如果重要的话,我使用PHP5。

14 个解决方案

#1


102  

require_once and include_once both require that the system keeps a log of what's already been included/required. Every *_once call means checking that log. So there's definitely some extra work being done there but enough to detriment the speed of the whole app?

require_once和include_once都要求系统保存已经包含/需要的内容的日志。每个*_once调用都意味着检查日志。所以肯定有一些额外的工作要做但足以损害整个程序的速度?

... I really doubt it... Not unless you're on really old hardware or doing it a lot.

…我真的怀疑…除非你用的是老旧的硬件或者做了很多。

If you are doing thousands of *_once, you could do the work yourself in a lighter fashion. For simple apps, just making sure you've only included it once should suffice but if you're still getting redefine errors, you could something like this:

如果你要做成千上万次,你可以用更轻松的方式自己做。对于简单的应用程序,只要确保只包含一次就足够了,但是如果你还在重新定义错误,你可以这样做:

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

I'll personally stick with the *_once statements but on silly million-pass benchmark, you can see a difference between the two:

我个人将坚持使用*_once语句,但是在愚蠢的百万通基准测试中,您可以看到两者之间的区别:

                php                  hhvm
if defined      0.18587779998779     0.046600103378296
require_once    1.2219581604004      3.2908599376678

10-100× slower with require_once and it's curious that require_once is seemingly slower in hhvm. Again, this is only relevant to your code if you're running *_once thousands of times.

10 - 100×慢require_once好奇,require_once hhvm看似慢。同样,这只与您的代码相关,如果您正在运行*_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.

#2


144  

This thread makes me cringe, because there's already been a "solution posted", and it's, for all intents and purposes, wrong. Let's enumerate:

这个线程让我畏缩,因为已经有了一个“发布的解决方案”,而且无论出于什么目的,它都是错误的。让我们列举:

  1. Defines are really expensive in PHP. You can look it up or test it yourself, but the only efficient way of defining a global constant in PHP is via an extension. (Class constants are actually pretty decent performance wise, but this is a moot point, because of 2)

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

  2. If you are using require_once() appropriately, that is, for inclusion of classes, you don't even need a define; just check if class_exists('Classname'). If the file you are including contains code, i.e. you're using it in the procedural fashion, there is absolutely no reason that require_once() should be necessary for you; each time you include the file you presume to be making a subroutine call.

    如果您适当地使用require_once(),也就是说,对于类的包含,您甚至不需要定义;只是检查是否class_exists(“类名”)。如果您所包含的文件包含代码,即您正在以过程方式使用它,那么绝对没有理由需要require_once();每次包含假定正在进行子例程调用的文件时。

So for a while, a lot of people did use the class_exists() method for their inclusions. I don't like it because it's fugly, but they had good reason to: require_once() was pretty inefficient before some of the more recent versions of PHP. But that's been fixed, and it is my contention that the extra bytecode you'd have to compile for the conditional, and the extra method call, would by far overweigh any internal hashtable check.

因此,有一段时间,很多人确实使用class_exist()方法进行包含。我不喜欢它,因为它很繁琐,但是他们有充分的理由:在PHP的一些较新的版本之前,require_once()非常低效。但这已经得到了修正,我的论点是,您必须为条件句编译的额外字节码和额外的方法调用,将远远超过任何内部hashtable检查。

Now, an admission: this stuff is tough to test for, because it accounts for so little of the execution time.

现在,承认一下:这个东西很难测试,因为它只占很少的执行时间。

Here is the question you should be thinking about: includes, as a general rule, are expensive in PHP, because every time the interpreter hits one it has to switch back into parse mode, generate the opcodes, and then jump back. If you have a 100+ includes, this will definitely have a performance impact. The reason why using or not using require_once is such an important question is because it makes life difficult for opcode caches. An explanation for this can be found here, but what this boils down to is that:

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

  • If during parse time, you know exactly what include files you will need for the entire life of the request, require() those at the very beginning and the opcode cache will handle everything else for you.

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

  • If you are not running an opcode cache, you're in a hard place. Inlining all of your includes into one file (don't do this during development, only in production) can certainly help parse time, but it's a pain to do, and also, you need to know exactly what you'll be including during the request.

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

  • Autoload is very convenient, but slow, for the reason that the autoload logic has to be run every time an include is done. In practice, I've found that autoloading several specialized files for one request does not cause too much of a problem, but you should not be autoloading all of the files you will need.

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

  • If you have maybe 10 includes (this is a very back of the envelope calculation), all this wanking is not worth it: just optimize your database queries or something.

    如果您有10个include(这是最基本的计算),那么所有这些都不值得:只需优化数据库查询或其他东西。

#3


64  

I got curious and checked out Adam Backstrom's link to Tech Your Universe. This article describes one of the reasons that require should be used instead of require_once. However, their claims didn't hold up to my analysis. I'd be interested in seeing where I may have misanalysed the solution. I used php 5.2.0 for comparisons.

我很好奇,查了亚当·贝克斯特伦的链接,发现了你的宇宙。本文描述了应该使用require而不是require_once的原因之一。然而,他们的说法并不符合我的分析。我很想知道我在哪里分析错了答案。我使用php 5.2.0进行比较。

I started out by creating 100 header files that used require_once to include another header file. Each of these files looked something like:

我首先创建了100个头文件,使用require_once包含另一个头文件。每个文件看起来都是这样的:

<?php
// /home/fbarnes/phpperf/hdr0.php
require_once "../phpperf/common_hdr.php";

?>

I created these using a quick bash hack:

我用一个快速的bash hack创建了这些:

for i in /home/fbarnes/phpperf/hdr{00..99}.php; do
  echo "<?php
// $i" > $i
  cat helper.php >> $i;
done

This way I could easily swap between using require_once and require when including the header files. I then created an app.php to load the one hundred files. This looked like:

通过这种方式,我可以轻松地在使用require_once和包含头文件时require之间进行切换。然后我创建了一个app.php来加载100个文件。这看起来像:

<?php

// Load all of the php hdrs that were created previously
for($i=0; $i < 100; $i++)
{
  require_once "/home/fbarnes/phpperf/hdr$i.php";
}

// Read the /proc file system to get some simple stats
$pid = getmypid();
$fp = fopen("/proc/$pid/stat", "r");
$line = fread($fp, 2048);
$array = split(" ", $line);

// write out the statistics; on RedHat 4.5 w/ kernel 2.6.9
// 14 is user jiffies; 15 is system jiffies
$cntr = 0;
foreach($array as $elem)
{
  $cntr++;
  echo "stat[$cntr]: $elem\n";
}
fclose($fp);

?>

I contrasted the require_once headers with require headers that used a header file looking like:

我将require_once头与使用头文件的头文件进行了对比:

<?php
// /home/fbarnes/phpperf/h/hdr0.php
if(!defined('CommonHdr'))
{
  require "../phpperf/common_hdr.php";
  define('CommonHdr', 1);
}

?>

I didn't find much difference when running this with require vs. require_once. In fact my initial tests seemed to imply that require_once was slightly faster, but I don't necessarily believe that. I repeated the experiment with 10000 input files. Here I did see a consistent difference. I ran the test multiple times, the results are close but using require_once uses on average 30.8 user jiffies and 72.6 system jiffies; using require uses on average 39.4 user jiffies and 72.0 system jiffies. Therefore, it appears that the load is slightly lower using require_once. However, wall clock is slightly increased. The 10,000 require_once calls use 10.15 seconds to complete on average and 10,000 require calls use 9.84 seconds on average.

在使用require和require_once运行时,我没有发现有什么不同。事实上,我最初的测试似乎暗示了require_once稍微快一点,但我并不一定相信这一点。我用10000个输入文件重复了这个实验。在这里,我确实看到了一致的差异。我多次运行测试,结果接近,但是使用require_once平均使用30.8个用户jiffies和72.6个系统jiffies;平均使用次数为39.4次,72.0次。因此,似乎使用require_once的负载稍低一些。然而,挂钟略有增加。10,000 require_once调用平均需要10.15秒完成,10,000需要调用平均需要9.84秒完成。

Next step is to look into these differences. I used strace to analyse the system calls that are being made.

下一步是研究这些差异。我用strace分析了正在进行的系统调用。

Before opening a file from require_once the following system calls are made:

在从require_once打开文件之前,进行以下系统调用:

time(NULL)                              = 1223772434
lstat64("/home", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf/h", {st_mode=S_IFDIR|0755, st_size=270336, ...}) = 0
lstat64("/home/fbarnes/phpperf/h/hdr0.php", {st_mode=S_IFREG|0644, st_size=88, ...}) = 0
time(NULL)                              = 1223772434
open("/home/fbarnes/phpperf/h/hdr0.php", O_RDONLY) = 3

This contrasts with require:

这与要求:

time(NULL)                              = 1223772905
lstat64("/home", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf/h", {st_mode=S_IFDIR|0755, st_size=270336, ...}) = 0
lstat64("/home/fbarnes/phpperf/h/hdr0.php", {st_mode=S_IFREG|0644, st_size=146, ...}) = 0
time(NULL)                              = 1223772905
open("/home/fbarnes/phpperf/h/hdr0.php", O_RDONLY) = 3

Tech Your Universe implies that require_once should make more lstat64 calls. However, they both make the same number of lstat64 calls. Possibly, the difference is that I am not running APC to optimize the code above. However, the next thing I did was compare the output of strace for the entire runs:

Tech Your Universe意味着require_once应该发出更多的lstat64调用。但是,它们都发出相同数量的lstat64调用。可能的区别是,我没有运行APC来优化上面的代码。然而,接下来我做的是比较strace在整个运行中的输出:

[fbarnes@myhost phpperf]$ wc -l strace_1000r.out strace_1000ro.out 
  190709 strace_1000r.out
  210707 strace_1000ro.out
  401416 total

Effectively there are approximately two more system calls per header file when using require_once. One difference is that require_once has an additional call to the time() function:

实际上,在使用require_once时,每个头文件大约有两个系统调用。一个区别是require_once有一个对time()函数的额外调用:

[fbarnes@myhost phpperf]$ grep -c time strace_1000r.out strace_1000ro.out 
strace_1000r.out:20009
strace_1000ro.out:30008

The other system call is getcwd():

另一个系统调用是getcwd():

[fbarnes@myhost phpperf]$ grep -c getcwd strace_1000r.out strace_1000ro.out 
strace_1000r.out:5
strace_1000ro.out:10004

This is called because I decided to relative path referenced in the hdrXXX files. If I make this an absolute reference, then the only difference is the additional time(NULL) call made in the code:

之所以调用它,是因为我决定在hdrXXX文件中引用相对路径。如果我将此设置为绝对引用,那么唯一的区别就是代码中附加的时间(NULL)调用:

[fbarnes@myhost phpperf]$ wc -l strace_1000r.out strace_1000ro.out 
  190705 strace_1000r.out
  200705 strace_1000ro.out
  391410 total
[fbarnes@myhost phpperf]$ grep -c time strace_1000r.out strace_1000ro.out
strace_1000r.out:20008
strace_1000ro.out:30008

This seems to imply that you could reduce the number of system calls by using absolute paths rather than relative paths. The only difference outside of that is the time(NULL) calls which appear to be used for instrumenting the code to compare what is faster.

这似乎意味着您可以通过使用绝对路径而不是相对路径来减少系统调用的数量。惟一的区别是时间(NULL)调用,它似乎是用来检测代码来比较更快的。

One other note is that the APC optimization package has an option called "apc.include_once_override" that claims that it reduces the number of system calls made by the require_once and include_once calls (see the PHP docs).

另一个注意事项是APC优化包有一个名为“APC”的选项。include_once_override“声称它减少了require_once和include_once调用的系统调用数量(请参阅PHP文档)。

Sorry for the long post. I got curious.

不好意思,我的邮件太长了。我很好奇。

#4


20  

Can you give us any links to these coding practices which say to avoid it? As far as I'm concerned, it's a complete non-issue. I haven't looked at the source code myself, but I'd imagine that the only difference between include and include_once is that include_once adds that filename to an array and checks over the array each time. It'd be easy to keep that array sorted, so searching over it should be O(log n), and even a medium-largish application would only have a couple of dozen includes.

你能给我们一些关于这些编码实践的链接吗?在我看来,这是完全没有问题的。我自己还没有查看源代码,但是我想include和include_once之间的唯一区别是include_once将文件名添加到一个数组中,并每次检查数组。保持数组排序是很容易的,所以在它上面搜索应该是O(log n),甚至一个中等大小的应用程序也只有几十个include。

#5


6  

A better way to do things is to use an object-oriented approach and use __autoload().

更好的方法是使用面向对象的方法并使用__autoload()。

#6


5  

The *_once() functions stat every parent directory to ensure the file you're including isn't the same as one that's already been included. That's part of the reason for the slowdown.

*_once()函数会统计每个父目录,以确保包含的文件与已经包含的文件不相同。这是经济放缓的部分原因。

I recommend using a tool like Siege for benchmarking. You can try all the suggested methodologies and compare response times.

我建议使用攻城这样的工具来做基准测试。您可以尝试所有建议的方法并比较响应时间。

More on require_once() at Tech Your Universe.

更多关于require_once()的信息,请访问您的宇宙。

#7


5  

The PEAR2 wiki (when it existed) used to list good reasons for abandoning all the require/include directives in favor of autoloading, at least for library code. These tie you down to rigid directory structures when alternative packaging models like phar are on the horizon.

PEAR2 wiki(当它存在的时候)曾经列出了放弃所有的需要/包含指令以支持自动读的好理由,至少对于库代码来说是这样的。当像phar这样的可选打包模型出现时,它们将您绑定到刚性目录结构上。

Update: As the web archived version of the wiki is eye-gougingly ugly, I've copied the most compelling reasons below:

更新:由于维基的网页存档版本丑陋得令人瞠目结舌,我复制了以下最引人注目的原因:

  • include_path is required in order to use a (PEAR) package. This makes it difficult to bundle a PEAR package within another application with its own include_path, to create a single file containing needed classes, to move a PEAR package to a phar archive without extensive source code modification.
  • 使用(PEAR)包需要include_path。这使得在另一个应用程序中很难将一个PEAR包与它自己的include_path捆绑在一起,创建一个包含所需类的单个文件,将一个PEAR包移到phar归档,而不需要修改大量的源代码。
  • when top-level require_once is mixed with conditional require_once, this can result in code that is uncacheable by opcode caches such as APC, which will be bundled with PHP 6.
  • 当*require_once与条件require_once混合时,这可能会导致由opcode缓存(如APC)不被缓存的代码,而APC将与PHP 6捆绑在一起。
  • relative require_once requires that include_path already be set up to the correct value, making it impossible to use a package without proper include_path
  • 相对的require_once要求include_path已经被设置为正确的值,使得在没有适当的include_path的情况下使用包是不可能的。

#8


5  

It's not using the function that is bad. It's an incorrect understanding of how and when to use it, in an overall code base. I'll just add a bit more context to that possibly misunderstood notion:

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

People shouldn't think that require_once is a slow function. You have to include your code one way or another. require_once() vs. require()'s speed isn't the issue. It's about the performance hindering caveats that may results for using it blindly. If used broadly without consideration for context, it can lead to huge memory waste or wasteful code.

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

What I have seen that's really bad, is when huge monolithic frameworks use require_once() in all the wrong ways, especially in a complex Object Oriented environment.

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

Take the example of using require_once() at the top of every class as seen in many libraries:

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

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

So the User class is designed to use all 3 other classes. Fair enough! But now what if a visitor is browsing the site and not even logged in and the framework loads: require_once("includes/user.php"); for every single request.

所以User类被设计成使用所有其他三个类。很好!但是现在,如果一个访问者正在浏览站点,甚至没有登录,并且框架加载了:require_once(“include /user.php”);对于每一个请求。

It's including 1+3 unnecessary classes it won't ever use during that particular request. This is how bloated frameworks end up using 40MB per request as opposed to 5MB or less.

它包含1+3个不必要的类,在这个特定的请求中不会用到。这就是膨胀的框架如何使用40MB /请求而不是5MB或更少。


The other ways it can be misused, is when a class is re-used by many others! Say you have about 50 classes that use helper functions. To make sure helpers are available for those classes when they are loaded, you get:

另一种可能被误用的方法是,当一个类被许多其他类重用时!假设您有大约50个使用helper函数的类。为了确保这些课程在加载时提供帮助,您可以获得:

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

There is nothing wrong here per se. However if one page request happens to include 15 similar classes. You are running require_once 15 times, or for a nice visual:

这本身没有什么问题。但是,如果一个页面请求恰好包含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");

The use of require_once() technically affects performance for running that function 14 times, on top of having to parse those unnecessary lines. With just 10 other highly used classes with that similar problem, it could account for 100+ lines of such rather pointless repetitive code.

require_once()的使用在技术上影响函数运行14次的性能,此外还必须解析那些不必要的行。如果只有其他10个高度使用的类有类似的问题,那么它就可以处理100多行这样毫无意义的重复代码。

With that, it's probably worth using require("includes/helpers.php"); at the bootstrap of your app or framework, instead. But since everything is relative, it all depends if the weight versus usage frequency of the helpers class is worth saving 15-100 lines of require_once(). But if the probability of not using the helpers file on any given request is none, then require should definitely be in your main class instead. Having require_once in each class separately becomes a waste of resources.

因此,使用require(“include /helper .php”)可能是值得的;在你的应用程序或框架的引导下。但是由于所有内容都是相对的,所以这完全取决于helper类的权重和使用频率是否值得节省15-100行require_once()。但是,如果在任何给定请求上不使用helper文件的概率为none,那么require肯定应该在主类中。在每个类中分别使用require_once会浪费资源。


The require_once function is useful when necessary, but it shouldn't be regarded as a monolithic solution to use everywhere for loading all classes.

require_once函数在必要的时候是有用的,但是它不应该被认为是一个整体解决方案,可以在任何地方加载所有的类。

#9


2  

Even if require_once and include_once are slower than require and include (or whatever alternatives might exist), we're talking about the smallest level of micro-optimization here. Your time is much better spent optimizing that poorly written loop or database query than worrying about something like require_once.

即使require_once和include_once都比require和include(或者其他可能存在的选项)慢,我们在这里讨论的是最小的微优化级别。与担心类似require_once这样的东西相比,花在优化编写糟糕的循环或数据库查询上的时间要好得多。

Now, one could make an argument saying that require_once allows for poor coding practices because you don't need to pay attention to keeping your includes clean and organized, but that has nothing to do with the function itself and especially not its speed.

现在,有人可能会说,require_once允许糟糕的编码实践,因为您不需要注意保持您的包括整洁和有组织,但是这与函数本身无关,尤其是它的速度。

Obviously, autoloading is better for the sake of code cleanliness and ease of maintenance, but I want to make it clear that this has nothing to do with speed.

显然,出于代码整洁和易于维护的考虑,自动加载更好,但我想明确一点,这与速度无关。

#10


0  

Yes, it is slightly more expensive than plain ol' require(). I think the point is if you can keep your code organized enough to not douplicate includes, don't use the *_once() functions, as it will save you some cycles.

是的,它比普通的要贵一点。我认为关键在于,如果你能让你的代码保持足够的条码,而不是一遍一遍,不要使用*_once()函数,因为它会为你节省一些周期。

But using the _once() functions isn't going to kill your app. Basically, just don't use it as an excuse to not have to organize your includes. In some cases, using it is still unavoidable, and it's not a big deal.

但是使用_once()函数并不会破坏你的应用程序。基本上,不要把它当作不用组织你的include的借口。在某些情况下,使用它仍然是不可避免的,这并不是什么大问题。

#11


0  

You test, using include, oli's alternative and __autoload(); and test it with something like APC installed.

您测试,使用include, oli可选的和__autoload();然后用类似APC的设备进行测试。

I doubt using constant will speed things up.

我怀疑用常数会加快速度。

#12


-2  

I think in PEAR documentation, there is a recommendation for require, require_once, include and include_once. I do follow that guideline. Your application would be more clear.

我认为在PEAR文档中,有一个关于require、require_once、include和include_once的建议。我确实遵循这条准则。你的申请会更清楚。

#13


-3  

It has nothing to do with speed. It's about failing gracefully.

它与速度无关。优雅地失败。

If require_once() fails, your script is done. Nothing else is processed. If you use include_once() the rest of your script will try to continue to render, so your users potentially would be none-the-wiser to something that has failed in your script.

如果require_once()失败,脚本就完成了。没有其他处理。如果您使用include_once(),脚本的其余部分将尝试继续呈现,因此您的用户可能对脚本中失败的内容并不了解。

#14


-4  

My personal opinion is that the usage of require_once (or include_once) is bad practice because require_once checks for you if you already included that file and suppress errors of double included files resulting in fatal errors (like duplicate declaration of functions/classes/etc.).

我个人的观点是,require_once(或include_once)的使用是很糟糕的实践,因为require_once检查过您是否已经包含了该文件,并消除了双重包含的文件的错误,导致了致命错误(如函数/类的重复声明等)。

You should know if you need to include a file.

您应该知道是否需要包含一个文件。

#1


102  

require_once and include_once both require that the system keeps a log of what's already been included/required. Every *_once call means checking that log. So there's definitely some extra work being done there but enough to detriment the speed of the whole app?

require_once和include_once都要求系统保存已经包含/需要的内容的日志。每个*_once调用都意味着检查日志。所以肯定有一些额外的工作要做但足以损害整个程序的速度?

... I really doubt it... Not unless you're on really old hardware or doing it a lot.

…我真的怀疑…除非你用的是老旧的硬件或者做了很多。

If you are doing thousands of *_once, you could do the work yourself in a lighter fashion. For simple apps, just making sure you've only included it once should suffice but if you're still getting redefine errors, you could something like this:

如果你要做成千上万次,你可以用更轻松的方式自己做。对于简单的应用程序,只要确保只包含一次就足够了,但是如果你还在重新定义错误,你可以这样做:

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

I'll personally stick with the *_once statements but on silly million-pass benchmark, you can see a difference between the two:

我个人将坚持使用*_once语句,但是在愚蠢的百万通基准测试中,您可以看到两者之间的区别:

                php                  hhvm
if defined      0.18587779998779     0.046600103378296
require_once    1.2219581604004      3.2908599376678

10-100× slower with require_once and it's curious that require_once is seemingly slower in hhvm. Again, this is only relevant to your code if you're running *_once thousands of times.

10 - 100×慢require_once好奇,require_once hhvm看似慢。同样,这只与您的代码相关,如果您正在运行*_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.

#2


144  

This thread makes me cringe, because there's already been a "solution posted", and it's, for all intents and purposes, wrong. Let's enumerate:

这个线程让我畏缩,因为已经有了一个“发布的解决方案”,而且无论出于什么目的,它都是错误的。让我们列举:

  1. Defines are really expensive in PHP. You can look it up or test it yourself, but the only efficient way of defining a global constant in PHP is via an extension. (Class constants are actually pretty decent performance wise, but this is a moot point, because of 2)

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

  2. If you are using require_once() appropriately, that is, for inclusion of classes, you don't even need a define; just check if class_exists('Classname'). If the file you are including contains code, i.e. you're using it in the procedural fashion, there is absolutely no reason that require_once() should be necessary for you; each time you include the file you presume to be making a subroutine call.

    如果您适当地使用require_once(),也就是说,对于类的包含,您甚至不需要定义;只是检查是否class_exists(“类名”)。如果您所包含的文件包含代码,即您正在以过程方式使用它,那么绝对没有理由需要require_once();每次包含假定正在进行子例程调用的文件时。

So for a while, a lot of people did use the class_exists() method for their inclusions. I don't like it because it's fugly, but they had good reason to: require_once() was pretty inefficient before some of the more recent versions of PHP. But that's been fixed, and it is my contention that the extra bytecode you'd have to compile for the conditional, and the extra method call, would by far overweigh any internal hashtable check.

因此,有一段时间,很多人确实使用class_exist()方法进行包含。我不喜欢它,因为它很繁琐,但是他们有充分的理由:在PHP的一些较新的版本之前,require_once()非常低效。但这已经得到了修正,我的论点是,您必须为条件句编译的额外字节码和额外的方法调用,将远远超过任何内部hashtable检查。

Now, an admission: this stuff is tough to test for, because it accounts for so little of the execution time.

现在,承认一下:这个东西很难测试,因为它只占很少的执行时间。

Here is the question you should be thinking about: includes, as a general rule, are expensive in PHP, because every time the interpreter hits one it has to switch back into parse mode, generate the opcodes, and then jump back. If you have a 100+ includes, this will definitely have a performance impact. The reason why using or not using require_once is such an important question is because it makes life difficult for opcode caches. An explanation for this can be found here, but what this boils down to is that:

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

  • If during parse time, you know exactly what include files you will need for the entire life of the request, require() those at the very beginning and the opcode cache will handle everything else for you.

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

  • If you are not running an opcode cache, you're in a hard place. Inlining all of your includes into one file (don't do this during development, only in production) can certainly help parse time, but it's a pain to do, and also, you need to know exactly what you'll be including during the request.

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

  • Autoload is very convenient, but slow, for the reason that the autoload logic has to be run every time an include is done. In practice, I've found that autoloading several specialized files for one request does not cause too much of a problem, but you should not be autoloading all of the files you will need.

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

  • If you have maybe 10 includes (this is a very back of the envelope calculation), all this wanking is not worth it: just optimize your database queries or something.

    如果您有10个include(这是最基本的计算),那么所有这些都不值得:只需优化数据库查询或其他东西。

#3


64  

I got curious and checked out Adam Backstrom's link to Tech Your Universe. This article describes one of the reasons that require should be used instead of require_once. However, their claims didn't hold up to my analysis. I'd be interested in seeing where I may have misanalysed the solution. I used php 5.2.0 for comparisons.

我很好奇,查了亚当·贝克斯特伦的链接,发现了你的宇宙。本文描述了应该使用require而不是require_once的原因之一。然而,他们的说法并不符合我的分析。我很想知道我在哪里分析错了答案。我使用php 5.2.0进行比较。

I started out by creating 100 header files that used require_once to include another header file. Each of these files looked something like:

我首先创建了100个头文件,使用require_once包含另一个头文件。每个文件看起来都是这样的:

<?php
// /home/fbarnes/phpperf/hdr0.php
require_once "../phpperf/common_hdr.php";

?>

I created these using a quick bash hack:

我用一个快速的bash hack创建了这些:

for i in /home/fbarnes/phpperf/hdr{00..99}.php; do
  echo "<?php
// $i" > $i
  cat helper.php >> $i;
done

This way I could easily swap between using require_once and require when including the header files. I then created an app.php to load the one hundred files. This looked like:

通过这种方式,我可以轻松地在使用require_once和包含头文件时require之间进行切换。然后我创建了一个app.php来加载100个文件。这看起来像:

<?php

// Load all of the php hdrs that were created previously
for($i=0; $i < 100; $i++)
{
  require_once "/home/fbarnes/phpperf/hdr$i.php";
}

// Read the /proc file system to get some simple stats
$pid = getmypid();
$fp = fopen("/proc/$pid/stat", "r");
$line = fread($fp, 2048);
$array = split(" ", $line);

// write out the statistics; on RedHat 4.5 w/ kernel 2.6.9
// 14 is user jiffies; 15 is system jiffies
$cntr = 0;
foreach($array as $elem)
{
  $cntr++;
  echo "stat[$cntr]: $elem\n";
}
fclose($fp);

?>

I contrasted the require_once headers with require headers that used a header file looking like:

我将require_once头与使用头文件的头文件进行了对比:

<?php
// /home/fbarnes/phpperf/h/hdr0.php
if(!defined('CommonHdr'))
{
  require "../phpperf/common_hdr.php";
  define('CommonHdr', 1);
}

?>

I didn't find much difference when running this with require vs. require_once. In fact my initial tests seemed to imply that require_once was slightly faster, but I don't necessarily believe that. I repeated the experiment with 10000 input files. Here I did see a consistent difference. I ran the test multiple times, the results are close but using require_once uses on average 30.8 user jiffies and 72.6 system jiffies; using require uses on average 39.4 user jiffies and 72.0 system jiffies. Therefore, it appears that the load is slightly lower using require_once. However, wall clock is slightly increased. The 10,000 require_once calls use 10.15 seconds to complete on average and 10,000 require calls use 9.84 seconds on average.

在使用require和require_once运行时,我没有发现有什么不同。事实上,我最初的测试似乎暗示了require_once稍微快一点,但我并不一定相信这一点。我用10000个输入文件重复了这个实验。在这里,我确实看到了一致的差异。我多次运行测试,结果接近,但是使用require_once平均使用30.8个用户jiffies和72.6个系统jiffies;平均使用次数为39.4次,72.0次。因此,似乎使用require_once的负载稍低一些。然而,挂钟略有增加。10,000 require_once调用平均需要10.15秒完成,10,000需要调用平均需要9.84秒完成。

Next step is to look into these differences. I used strace to analyse the system calls that are being made.

下一步是研究这些差异。我用strace分析了正在进行的系统调用。

Before opening a file from require_once the following system calls are made:

在从require_once打开文件之前,进行以下系统调用:

time(NULL)                              = 1223772434
lstat64("/home", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf/h", {st_mode=S_IFDIR|0755, st_size=270336, ...}) = 0
lstat64("/home/fbarnes/phpperf/h/hdr0.php", {st_mode=S_IFREG|0644, st_size=88, ...}) = 0
time(NULL)                              = 1223772434
open("/home/fbarnes/phpperf/h/hdr0.php", O_RDONLY) = 3

This contrasts with require:

这与要求:

time(NULL)                              = 1223772905
lstat64("/home", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf/h", {st_mode=S_IFDIR|0755, st_size=270336, ...}) = 0
lstat64("/home/fbarnes/phpperf/h/hdr0.php", {st_mode=S_IFREG|0644, st_size=146, ...}) = 0
time(NULL)                              = 1223772905
open("/home/fbarnes/phpperf/h/hdr0.php", O_RDONLY) = 3

Tech Your Universe implies that require_once should make more lstat64 calls. However, they both make the same number of lstat64 calls. Possibly, the difference is that I am not running APC to optimize the code above. However, the next thing I did was compare the output of strace for the entire runs:

Tech Your Universe意味着require_once应该发出更多的lstat64调用。但是,它们都发出相同数量的lstat64调用。可能的区别是,我没有运行APC来优化上面的代码。然而,接下来我做的是比较strace在整个运行中的输出:

[fbarnes@myhost phpperf]$ wc -l strace_1000r.out strace_1000ro.out 
  190709 strace_1000r.out
  210707 strace_1000ro.out
  401416 total

Effectively there are approximately two more system calls per header file when using require_once. One difference is that require_once has an additional call to the time() function:

实际上,在使用require_once时,每个头文件大约有两个系统调用。一个区别是require_once有一个对time()函数的额外调用:

[fbarnes@myhost phpperf]$ grep -c time strace_1000r.out strace_1000ro.out 
strace_1000r.out:20009
strace_1000ro.out:30008

The other system call is getcwd():

另一个系统调用是getcwd():

[fbarnes@myhost phpperf]$ grep -c getcwd strace_1000r.out strace_1000ro.out 
strace_1000r.out:5
strace_1000ro.out:10004

This is called because I decided to relative path referenced in the hdrXXX files. If I make this an absolute reference, then the only difference is the additional time(NULL) call made in the code:

之所以调用它,是因为我决定在hdrXXX文件中引用相对路径。如果我将此设置为绝对引用,那么唯一的区别就是代码中附加的时间(NULL)调用:

[fbarnes@myhost phpperf]$ wc -l strace_1000r.out strace_1000ro.out 
  190705 strace_1000r.out
  200705 strace_1000ro.out
  391410 total
[fbarnes@myhost phpperf]$ grep -c time strace_1000r.out strace_1000ro.out
strace_1000r.out:20008
strace_1000ro.out:30008

This seems to imply that you could reduce the number of system calls by using absolute paths rather than relative paths. The only difference outside of that is the time(NULL) calls which appear to be used for instrumenting the code to compare what is faster.

这似乎意味着您可以通过使用绝对路径而不是相对路径来减少系统调用的数量。惟一的区别是时间(NULL)调用,它似乎是用来检测代码来比较更快的。

One other note is that the APC optimization package has an option called "apc.include_once_override" that claims that it reduces the number of system calls made by the require_once and include_once calls (see the PHP docs).

另一个注意事项是APC优化包有一个名为“APC”的选项。include_once_override“声称它减少了require_once和include_once调用的系统调用数量(请参阅PHP文档)。

Sorry for the long post. I got curious.

不好意思,我的邮件太长了。我很好奇。

#4


20  

Can you give us any links to these coding practices which say to avoid it? As far as I'm concerned, it's a complete non-issue. I haven't looked at the source code myself, but I'd imagine that the only difference between include and include_once is that include_once adds that filename to an array and checks over the array each time. It'd be easy to keep that array sorted, so searching over it should be O(log n), and even a medium-largish application would only have a couple of dozen includes.

你能给我们一些关于这些编码实践的链接吗?在我看来,这是完全没有问题的。我自己还没有查看源代码,但是我想include和include_once之间的唯一区别是include_once将文件名添加到一个数组中,并每次检查数组。保持数组排序是很容易的,所以在它上面搜索应该是O(log n),甚至一个中等大小的应用程序也只有几十个include。

#5


6  

A better way to do things is to use an object-oriented approach and use __autoload().

更好的方法是使用面向对象的方法并使用__autoload()。

#6


5  

The *_once() functions stat every parent directory to ensure the file you're including isn't the same as one that's already been included. That's part of the reason for the slowdown.

*_once()函数会统计每个父目录,以确保包含的文件与已经包含的文件不相同。这是经济放缓的部分原因。

I recommend using a tool like Siege for benchmarking. You can try all the suggested methodologies and compare response times.

我建议使用攻城这样的工具来做基准测试。您可以尝试所有建议的方法并比较响应时间。

More on require_once() at Tech Your Universe.

更多关于require_once()的信息,请访问您的宇宙。

#7


5  

The PEAR2 wiki (when it existed) used to list good reasons for abandoning all the require/include directives in favor of autoloading, at least for library code. These tie you down to rigid directory structures when alternative packaging models like phar are on the horizon.

PEAR2 wiki(当它存在的时候)曾经列出了放弃所有的需要/包含指令以支持自动读的好理由,至少对于库代码来说是这样的。当像phar这样的可选打包模型出现时,它们将您绑定到刚性目录结构上。

Update: As the web archived version of the wiki is eye-gougingly ugly, I've copied the most compelling reasons below:

更新:由于维基的网页存档版本丑陋得令人瞠目结舌,我复制了以下最引人注目的原因:

  • include_path is required in order to use a (PEAR) package. This makes it difficult to bundle a PEAR package within another application with its own include_path, to create a single file containing needed classes, to move a PEAR package to a phar archive without extensive source code modification.
  • 使用(PEAR)包需要include_path。这使得在另一个应用程序中很难将一个PEAR包与它自己的include_path捆绑在一起,创建一个包含所需类的单个文件,将一个PEAR包移到phar归档,而不需要修改大量的源代码。
  • when top-level require_once is mixed with conditional require_once, this can result in code that is uncacheable by opcode caches such as APC, which will be bundled with PHP 6.
  • 当*require_once与条件require_once混合时,这可能会导致由opcode缓存(如APC)不被缓存的代码,而APC将与PHP 6捆绑在一起。
  • relative require_once requires that include_path already be set up to the correct value, making it impossible to use a package without proper include_path
  • 相对的require_once要求include_path已经被设置为正确的值,使得在没有适当的include_path的情况下使用包是不可能的。

#8


5  

It's not using the function that is bad. It's an incorrect understanding of how and when to use it, in an overall code base. I'll just add a bit more context to that possibly misunderstood notion:

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

People shouldn't think that require_once is a slow function. You have to include your code one way or another. require_once() vs. require()'s speed isn't the issue. It's about the performance hindering caveats that may results for using it blindly. If used broadly without consideration for context, it can lead to huge memory waste or wasteful code.

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

What I have seen that's really bad, is when huge monolithic frameworks use require_once() in all the wrong ways, especially in a complex Object Oriented environment.

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

Take the example of using require_once() at the top of every class as seen in many libraries:

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

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

So the User class is designed to use all 3 other classes. Fair enough! But now what if a visitor is browsing the site and not even logged in and the framework loads: require_once("includes/user.php"); for every single request.

所以User类被设计成使用所有其他三个类。很好!但是现在,如果一个访问者正在浏览站点,甚至没有登录,并且框架加载了:require_once(“include /user.php”);对于每一个请求。

It's including 1+3 unnecessary classes it won't ever use during that particular request. This is how bloated frameworks end up using 40MB per request as opposed to 5MB or less.

它包含1+3个不必要的类,在这个特定的请求中不会用到。这就是膨胀的框架如何使用40MB /请求而不是5MB或更少。


The other ways it can be misused, is when a class is re-used by many others! Say you have about 50 classes that use helper functions. To make sure helpers are available for those classes when they are loaded, you get:

另一种可能被误用的方法是,当一个类被许多其他类重用时!假设您有大约50个使用helper函数的类。为了确保这些课程在加载时提供帮助,您可以获得:

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

There is nothing wrong here per se. However if one page request happens to include 15 similar classes. You are running require_once 15 times, or for a nice visual:

这本身没有什么问题。但是,如果一个页面请求恰好包含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");

The use of require_once() technically affects performance for running that function 14 times, on top of having to parse those unnecessary lines. With just 10 other highly used classes with that similar problem, it could account for 100+ lines of such rather pointless repetitive code.

require_once()的使用在技术上影响函数运行14次的性能,此外还必须解析那些不必要的行。如果只有其他10个高度使用的类有类似的问题,那么它就可以处理100多行这样毫无意义的重复代码。

With that, it's probably worth using require("includes/helpers.php"); at the bootstrap of your app or framework, instead. But since everything is relative, it all depends if the weight versus usage frequency of the helpers class is worth saving 15-100 lines of require_once(). But if the probability of not using the helpers file on any given request is none, then require should definitely be in your main class instead. Having require_once in each class separately becomes a waste of resources.

因此,使用require(“include /helper .php”)可能是值得的;在你的应用程序或框架的引导下。但是由于所有内容都是相对的,所以这完全取决于helper类的权重和使用频率是否值得节省15-100行require_once()。但是,如果在任何给定请求上不使用helper文件的概率为none,那么require肯定应该在主类中。在每个类中分别使用require_once会浪费资源。


The require_once function is useful when necessary, but it shouldn't be regarded as a monolithic solution to use everywhere for loading all classes.

require_once函数在必要的时候是有用的,但是它不应该被认为是一个整体解决方案,可以在任何地方加载所有的类。

#9


2  

Even if require_once and include_once are slower than require and include (or whatever alternatives might exist), we're talking about the smallest level of micro-optimization here. Your time is much better spent optimizing that poorly written loop or database query than worrying about something like require_once.

即使require_once和include_once都比require和include(或者其他可能存在的选项)慢,我们在这里讨论的是最小的微优化级别。与担心类似require_once这样的东西相比,花在优化编写糟糕的循环或数据库查询上的时间要好得多。

Now, one could make an argument saying that require_once allows for poor coding practices because you don't need to pay attention to keeping your includes clean and organized, but that has nothing to do with the function itself and especially not its speed.

现在,有人可能会说,require_once允许糟糕的编码实践,因为您不需要注意保持您的包括整洁和有组织,但是这与函数本身无关,尤其是它的速度。

Obviously, autoloading is better for the sake of code cleanliness and ease of maintenance, but I want to make it clear that this has nothing to do with speed.

显然,出于代码整洁和易于维护的考虑,自动加载更好,但我想明确一点,这与速度无关。

#10


0  

Yes, it is slightly more expensive than plain ol' require(). I think the point is if you can keep your code organized enough to not douplicate includes, don't use the *_once() functions, as it will save you some cycles.

是的,它比普通的要贵一点。我认为关键在于,如果你能让你的代码保持足够的条码,而不是一遍一遍,不要使用*_once()函数,因为它会为你节省一些周期。

But using the _once() functions isn't going to kill your app. Basically, just don't use it as an excuse to not have to organize your includes. In some cases, using it is still unavoidable, and it's not a big deal.

但是使用_once()函数并不会破坏你的应用程序。基本上,不要把它当作不用组织你的include的借口。在某些情况下,使用它仍然是不可避免的,这并不是什么大问题。

#11


0  

You test, using include, oli's alternative and __autoload(); and test it with something like APC installed.

您测试,使用include, oli可选的和__autoload();然后用类似APC的设备进行测试。

I doubt using constant will speed things up.

我怀疑用常数会加快速度。

#12


-2  

I think in PEAR documentation, there is a recommendation for require, require_once, include and include_once. I do follow that guideline. Your application would be more clear.

我认为在PEAR文档中,有一个关于require、require_once、include和include_once的建议。我确实遵循这条准则。你的申请会更清楚。

#13


-3  

It has nothing to do with speed. It's about failing gracefully.

它与速度无关。优雅地失败。

If require_once() fails, your script is done. Nothing else is processed. If you use include_once() the rest of your script will try to continue to render, so your users potentially would be none-the-wiser to something that has failed in your script.

如果require_once()失败,脚本就完成了。没有其他处理。如果您使用include_once(),脚本的其余部分将尝试继续呈现,因此您的用户可能对脚本中失败的内容并不了解。

#14


-4  

My personal opinion is that the usage of require_once (or include_once) is bad practice because require_once checks for you if you already included that file and suppress errors of double included files resulting in fatal errors (like duplicate declaration of functions/classes/etc.).

我个人的观点是,require_once(或include_once)的使用是很糟糕的实践,因为require_once检查过您是否已经包含了该文件,并消除了双重包含的文件的错误,导致了致命错误(如函数/类的重复声明等)。

You should know if you need to include a file.

您应该知道是否需要包含一个文件。