是否可以在PHP 5.2.x中模拟闭包而不使用全局变量?

时间:2010-02-05 18:12:25

标签: php closures global-variables simulate

是否可以在PHP 5.2.x中模拟不使用全局变量的闭包?我可以想到一种方法可以将所需的变量作为额外的参数传递给闭包,但这并不是最佳实践。

有什么想法吗?

4 个答案:

答案 0 :(得分:7)

有趣的问题。我会说根本不可能,但让我们看看

引用IBM - What's new in PHP5.3, Part 2

  

闭包是一个在自己的环境中计算的函数,它有一个或多个绑定变量,可以在调用函数时访问它们。

并进一步(强调我的)

  来自外部环境的

要导入的变量在闭包函数定义的use子句中指定。默认情况下,它们按值传递,这意味着如果我们更新在闭包函数定义中传递的值,它将不会更新外部值。

使用global将通过引用传递,虽然可以使用&子句中的use通过引用将变量绑定到闭包,但它已经偏离了5.3默认行为。

$var = 'yes';
$fn  = create_function('', 'global $var; $var = "no";');
$fn();
echo $var; // outputs no

您可以复制全局变量,以便按值使用它,例如

$var = 'yes';
$fn  = create_function('', 'global $var; $tmp = $var; $tmp = "no";');
$fn();
echo $var; // outputs yes

此外,在创建函数但运行函数时,不会评估(绑定)全局变量的值(使用create_function时)

$var = 'yes';
$fn  = create_function('', 'global $var; $tmp = $var; return $tmp;');
$var = 'maybe';
echo $fn(); // outputs maybe

$var = 'yes';
$fn  = function() use ($var) { return $var; };
$var = 'maybe';
echo $fn(); // outputs yes

同样重要的是

  

在对象中定义时,一个方便的事情是闭包通过$ this变量可以完全访问对象,而无需显式导入它。 *虽然我认为这在最终的PHP5.3中被删除

使用global关键字无法做到这一点,您也不能只使用$this。在使用create_function定义函数体时,无法从类中引用属性。

class A {

    protected $prop = 'it works';

    public function test()
    {
        $fn = create_function('', 'echo $this->prop;');
        return $fn;
    }
}

$a = new A;
$fn = $a->test();
$fn();

将导致

Fatal error: Using $this when not in object context

总结一下
虽然您可以创建从全局范围导入变量的函数,但您不能使用另一个范围中的变量创建一个函数。并且因为你在使用create_function时技术上没有约束力,但是在执行创建的函数时导入,我想认为这个限制使得闭包成为一个lambda


编辑:Onno Marsman提供的解决方案虽然相当不错。它没有完全模拟闭包,但实现非常接近。

答案 1 :(得分:3)

我的解决方案:http://techblog.triptic.nl/simulating-closures-in-php-versions-prior-to-php-5-3/

然而,它确实将对象中的变量作为第一个参数传递给闭包。

答案 2 :(得分:2)

你的意思是像http://en.wikipedia.org/wiki/Currying

那样的哭泣

然后http://zaemis.blogspot.com/2009/06/currying-in-php.html

如果没有,请不要介意。 : - )

答案 3 :(得分:1)

在某些特殊情况下,您可以这样做。

如果需要按值(而不是通过引用)捕获变量,并且值是一个简单的值类型,如上面的数字,字符串或数组(不是对象,资源和函数等引用类型),那么您只需使用var_export()

将其插入到函数定义中即可
$var = array(1, 3);
$f = create_function('',
    '$var=' . var_export($var,true) . '; return $var;');

如果需要通过引用捕获变量以便在函数调用之间保持可变状态,但是您不需要将更改反映在创建它的原始范围内(例如,创建累加器,但是对sum的更改不需要更改创建范围中的sum变量),然后您可以类似地插入它,但作为静态变量:

function make_accumulator($sum) {
    $f = create_function('$x',
        'static $var=' . var_export($var,true) . '; return $var += $x;');
    return $f;
}