PHP 是不是包含资源昂贵(特别是在迭代期间)?

Posted

技术标签:

【中文标题】PHP 是不是包含资源昂贵(特别是在迭代期间)?【英文标题】:Is PHP's include resource-expensive (particularly during iterations)?PHP 是否包含资源昂贵(特别是在迭代期间)? 【发布时间】:2011-09-21 10:00:54 【问题描述】:

php 是否缓存 include 请求?我想知道如何清理我的代码,并考虑使用更多includes。考虑以下方案。

[foreach answer] [include answer.tpl.php] [/foreach]

这需要包含answer.tpl.php 数百次。

它会缓存吗?它会对性能产生值得考虑的影响吗? 这被认为是一种好习惯吗?不好?

回应@Aaron Murray 的回答

不,这行不通。 _once 的唯一概念是防止多次包含同一个文件。 (防止因覆盖常量值等引起的错误)

实际示例如下所示:

# index.php
<?php
$array  = array('a', 'b', 'c');

$output = '';

foreach($array as $e)

    $output .= require_once 'test.php';


echo $output;

# test.php 
<?php
return $e;

【问题讨论】:

文件的内容将被 OS 文件缓存缓存,但仍然会有开销执行 stat() 调用等以查看自上次加载以来文件是否已更改。 更不用说必须解析文件的内容并评估其中的所有 PHP 代码(如果有的话)。 require_once 没有返回值。这不是一个函数。 操作系统很好地缓存了隐含的文件请求。 PHP 本身没有。但这通常是无关紧要的,因为现在字节码缓存 (APC) 非常普遍。 @mario:我确实使用 APC。那么,如果 APC 正在使用中,这有点意味着 include 也被缓存了? 【参考方案1】:

PHP 是否缓存 include 请求?

据我所知,PHP 默认不缓存包含。但是您的底层文件系统可能会这样做。因此,在您的示例中一遍又一遍地访问同一个文件应该很快。

如果您遇到实际问题,您首先需要分析应用程序以找出实际瓶颈所在。因此,除非您还没有遇到任何问题,否则我会考虑使用无害的包含。

关于良好实践,我认为这篇文章对此进行了很好的解释:When Flat PHP meets Symfony。

让您的代码更具可重用性

这并不是什么高大上的设计,只是为了展示如何开始让事情变得更加模块化。您应该能够从包含文件中获取 1:1 的代码,只需注意将所有需要的模板变量传递到函数中(不要为此使用全局变量,它迟早会妨碍您):

# in your answer.tpl.php

function answer_template(array $vars) 
    extract($vars);
    ... your template code ...


# your script

array  = array('a', 'b', 'c');

$output = '';

require('answer.tpl.php');

foreach($array as $e)

    $output .= answer_template(compact('e'));


echo $output;

【讨论】:

感谢您的回答。不过,-1 表示 Symfony 和 afaik 的参考链接。以糟糕的方式编写代码并仅在代码损坏(或您开始遇到资源问题)时进行修复通常是一个糟糕的建议。 @Guy:链接的文章展示了一张一般的图片。它并没有隐瞒它来自 symfony,但不管任何类型的框架,它都是一本好书。不要仅仅因为标题而判断。第二点是,过早的优化往往是问题的根源,而不是解决方案。在查看您的代码时,我会首先考虑一些设计改进,然后再推测磁盘 I/O。因此,这不是一个忽略问题的建议,而是专门针对正确定位问题的建议。【参考方案2】:

您是否考虑过:

require_once('answer.tpl.php')
or
include_once('answer.tpl.php')

当然,您可以仅在您希望它们包含的脚本中包含“必需”文件(仅在真正需要它们的地方)。

编辑:修改答案:

index.php ->

require_once('answer.php');
echo answer(); // This function can be called from anywhere in the scripts.

answer.php ->

function answer() 
    return '<div>This is the answer</div>';

另外,您可以在函数中使用输出缓冲来在 answer.php 中捕获 html(用于分离 HTML 和 php 的更简洁的方法)。

回应你上面的例子:

index.php

<?php
require_once('test.php');
$array  = array('a', 'b', 'c');
$output = '';
foreach($array as $e)

    $output .= test($e);

echo $output;

test.php

<?php
    function test($param) 
    return $param;

【讨论】:

如果只包含一次,其余迭代会发生什么? _once 的概念是不允许多次包含相同的代码。 The require_once() statement is identical to require() except PHP will check if the file has already been included, and if so, not include (require) it again. 来自php.net 在模板的情况下,您可以将输出包装在一个函数或类中,然后 require_once 文件,然后从多个位置调用它。例如 answer.tpl.php -> function answer() echo '&lt;div&gt;This is my output&lt;/div&gt;'; 并在需要它的脚本中:echo answer() 当然,您也可以将参数传递添加到您创建的函数/类。 因此,您可以在调用脚本的顶部需要它一次,并在整个执行过程中使用该函数或类。【参考方案3】:

这个话题之前出现过,所以这里有一些潜在的重复(不认可任何;大部分是部分答案,但相关阅读):

What's the performance cost of "include" in PHP? Is it bad to include a lot of files in PHP like it is for file based Sessions? Will reducing number of includes/requires increase performance? Why is require_once so bad to use? Which is better performance in PHP?

嗯,这些都没有专门回答你的问题。我们在某处有一点性能基准,但我找不到。

(我个人经常组织我的代码以将整个应用程序合并到一个 blob 文件中,然后去除空格,以避免多个文件访问,即使 APC 存在。)

【讨论】:

以上是关于PHP 是不是包含资源昂贵(特别是在迭代期间)?的主要内容,如果未能解决你的问题,请参考以下文章

Python之迭代器生成器装饰器和递归

有人可以推荐一个关于 MySQL 索引的好教程,特别是在连接期间在 order by 子句中使用时? [关闭]

Java中的集合(十五) Iterator 和 ListIteratorEnumeration

Java中的集合(十五) Iterator 和 ListIteratorEnumeration

Plpgsql - 多次迭代记录集

优化昂贵的 php 查询/子查询