PHP 中的闭包或 create_function

Posted

技术标签:

【中文标题】PHP 中的闭包或 create_function【英文标题】:Closures or create_function in PHP 【发布时间】:2011-09-23 01:00:21 【问题描述】:

我决定在我的回调中使用闭包而不是 create_function,因此只支持 php > 5.3,主要是因为增加了可调试性,也因为我假设(他们对假设有什么看法?)在我的情况下,create_function 的即时编译的开销可能会抵消任何额外的比较,并且必须在函数中进行。

情况可能仍然如此(对于我的应用程序)并且需要进一步测试,但我对这个(非常)简单测试的输出很感兴趣,它表明 create_function 方法的速度是当它只能删除四个条件(和连接)时的闭包。显然,在我的测试用例中没有进行额外的处理,这就是大部分速度将获得或损失的地方,但是在您几乎没有额外处理但有很多条件(可以删除)和回调被调用了足够多次我开始认为使用create_function 可能会更好。

但是create_functioneval 之间有明显的相似之处,我对此持谨慎态度。

所以主要问题是使用create_function 创建的匿名函数与闭包创建的匿名函数有什么区别?

我正在考虑的几个具体问题是,当eval 功能被禁用时,create_function 是否还能工作?而且,我确定我最近在某处读到 create_function 函数即使声明为内部函数也会污染全局(或类)命名空间,但闭包不会。我现在找不到对此的参考,但这些陈述中的一个或两个都是真的吗?


这是我跑的小测试:

<?php

function foo($a=true, $b=true, $c=true, $d=true)

    $inner1 = create_function(
        '', 
        '$r = \''.($a ? 'a' : '').
                  ($b ? 'b' : '').
                  ($c ? 'c' : '').
                  ($d ? 'd' : '').'\';
         return $r;'
    );  


    $inner2 = function() use ($a, $b, $c, $d) 
       
        $r = ''; 
        if($a)  $r .= 'a'; 
        if($b)  $r .= 'b'; 
        if($c)  $r .= 'c'; 
        if($d)  $r .= 'd'; ;
        return $r; 
    ;  


    $time = microtime(true);
    for ($x=0; $x<99999; ++$x)
       
        $i1out = $inner1();
       
    echo '1:'.(microtime(true)-$time).'<br>';

    $time = microtime(true);
    for ($x=0; $x<99999; ++$x)
       
        $i2out = $inner2();
       
    echo '2:'.(microtime(true)-$time).'<br>';

    echo var_dump($i1out===$i2out).'<br>';


foo();

【问题讨论】:

应该很容易测试在哪个命名空间create_function.. 创建函数.. :) 我也会去关闭。在速度方面,也许你应该用真实的案例场景来测试它。我不确定为什么那个应该慢得多,但我会接受“打击”。此外,APC 在这种情况下是否有所作为?闭包是否缓存在操作码中?它也可能会有所作为。 把它们分开。这个问题已经……很长了。 @phihag 你是对的,它很长,所以它完成了。 【参考方案1】:

function() .. 的构造是一个匿名函数,这个特性经常与closures 一起实现。 create_function 和匿名函数都不会污染全局命名空间。

由于匿名函数可以访问周围的变量(闭包部分),理论上它们可以稍微慢一些。另一方面,如果你使用字节码缓存(如果你不使用,你显然不关心性能),我预计匿名函数的“编译”开销会稍微慢一些。

但是,匿名函数和create_function 之间的差异极不可能是性能问题的根源。因此,如果您有幸拥有 php>5.3 的目标平台,我会选择更易读的匿名函数形式。

【讨论】:

嗯,这取决于您所说的“污染全局命名空间”是什么意思。 create_function 确实创建了一个全局函数,但它的名称不会与您用于函数的名称冲突。【参考方案2】:

create_function 创建一个全局函数,该函数对程序的其余部分持续存在。 create_function 只返回函数名(一个字符串),因此不知道您是否仍然可以访问以某种方式存储在某处的该名称。因此,它不能被“垃圾收集”,即使您不再有权访问该名称。

这意味着一个大问题是如果你使用create_function创建了很多函数,它会导致你的程序内存不足:

for ($i = 0; $i < 1000000; $i++) 
  $f = create_function('', '');
  // do stuff

  // don't use $f anywhere after this point

而对于匿名函数,这不会发生(闭包将被垃圾收集)。

【讨论】:

以上是关于PHP 中的闭包或 create_function的主要内容,如果未能解决你的问题,请参考以下文章

PHP中的闭包和匿名函数

带有字符串键或嵌套引号的数组到 php 中的 lambda 函数中

转:php中的匿名函数和闭包(closure)

php : 匿名函数(闭包) [一]

什么是 PHP 中的 Closures/Lambda 或 Javascript 中的外行术语? [复制]

浅析PHP中的闭包和匿名函数