9

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

有任何想法吗?

4

4 回答 4

8

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

引用IBM - PHP5.3 中的新增功能,第 2 部分

闭包是在自己的环境中评估的函数,它具有一个或多个绑定变量,在调用函数时可以访问这些变量。

并进一步(强调我的)

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

Usingglobal将通过引用传递,尽管可以通过&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 提供的解决方案相当不错。它没有完全模拟闭包,但实现非常接近。

于 2010-02-05T18:54:47.790 回答
3

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

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

于 2010-03-31T21:32:07.923 回答
2

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

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

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

于 2010-02-05T18:39:13.707 回答
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;
}
于 2011-10-28T05:19:44.677 回答