PHP中的闭包或create_function

3
我决定在回调中使用闭包而不是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 在哪个命名空间中创建函数应该很容易 :) - Karoly Horvath
我也会选择闭包。就速度而言,也许你应该用真实的案例来测试它。我不确定为什么一个会慢那么多,但我会承受这个“打击”。此外,在这种情况下,APC有影响吗?闭包是否被缓存在opcode中?这也可能会有所不同。 - Arend
把它们分开。这个问题已经太长了。 - phihag
@phihag 没错,这确实很长,所以已经完成了。 - tjm
2个回答

6
构造函数function() {..} 是一个匿名函数,这个特性通常与闭包一起实现。无论是create_function还是匿名函数都不会污染全局命名空间。
由于匿名函数可以访问周围的变量(闭包部分),理论上它们可能会稍微慢一些。另一方面,如果您正在使用字节码缓存(如果没有,您显然不关心性能),我预计匿名函数的“编译”开销会稍微慢一些。
然而,匿名函数和create_function之间的差异极不可能成为性能问题的源头。因此,如果你有一个目标平台,php>5.3,我会选择更易读的匿名函数形式。

1
这取决于你所说的“污染全局命名空间”的含义。create_function确实会创建一个全局函数,但它的名称不会与你用于自己的函数的名称发生冲突。 - newacct

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
}

相比之下,使用匿名函数就不会发生这种情况(闭包将被垃圾回收)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接