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

发布于 2024-08-20 01:54:36 字数 95 浏览 12 评论 0原文

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

有什么想法吗?

Is it possible to simulate closures in PHP 5.2.x not using globals? I could think of a way that would pass the desired variables as extra parameters to the closure but that just doesn't feel like best practice.

Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

那伤。 2024-08-27 01:54:36

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

引用IBM - PHP5.3 中的新增功能,第 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 提供的解决方案相当不错。它没有完全模拟闭包,但实现非常接近。

Interesting question. I'd say it's not possible at all, but let's see

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

A closure is a function that is evaluated in its own environment, which has one or more bound variables that can be accessed when the function is called.

and further (emphasis mine)

Variables to be imported from the outside environment are specified in the use clause of the closure function definition. By default, they are passed by value, meaning that if we would update the value passed within the closure function definition, it would not update the outside value.

Using global would pass by reference and although it is possible to bind variables by reference with a closure by using & in the use clause, it is already a deviation from the 5.3 default behavior.

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

You could copy the global variable in order to use it by value though, e.g.

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

In addition, the value of the global variable (when using create_function) will not be evaluated (bound) when the function is created but when the function is run

$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

Also important is

When defined within an object, one handy thing is that the closure has full access to the object through the $this variable, without the need to import it explicitly. *Though I think this was dropped in final PHP5.3

This is impossible with the global keyword and you also cannot just use $this. There is no way to reference a property from a class when defining the function body with 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();

will result in

Fatal error: Using $this when not in object context

To sum this up
While you can create a function importing a variable from the global scope, you cannot cannot create one using variables from another scope. And because you are technically not binding when using create_function but importing when the created function is executed, I'd like to argue this limitation makes the closure a lambda.


EDIT: The solution offered by Onno Marsman below is pretty decent though. It doesn't fully simulate Closures, but the implementation is pretty close.

长伴 2024-08-27 01:54:36

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

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

My solution: http://techblog.triptic.nl/simulating-closures-in-php-versions-prior-to-php-5-3/

It does however pass the variables within an object to the closure as the first argument.

打小就很酷 2024-08-27 01:54:36

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

然后< a href="http://zaemis.blogspot.com/2009/06/currying-in-php.html" rel="nofollow noreferrer">http://zaemis.blogspot.com/2009/06/currying-in -php.html

如果没有,没关系。 :-)

疑心病 2024-08-27 01:54:36

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

如果您需要按值(而不是按引用)捕获变量,并且该值是简单的值类型,如数字、字符串或上述数组(而不是对象、资源和函数等引用类型),那么您可以简单地使用 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;
}

There are some special cases where you can do it.

If you need to capture a variable by value (not by reference), and the value is a simple value type like a number, string, or array of the above (not reference types like objects and resources and functions), then you can simply insert it into the function definition using var_export():

$var = array(1, 3);
$f = create_function('',
    '$var=' . var_export($var,true) . '; return $var;');

If you need to capture the variable by reference in order to maintain mutable state across calls of the function, but you don't need to have the changes reflected in the original scope where it's created (e.g. to create an accumulator, but the changes to the sum don't need to change the sum variable in the creating scope), then you can similarly insert it, but as a static variable:

function make_accumulator($sum) {
    $f = create_function('$x',
        'static $var=' . var_export($var,true) . '; return $var += $x;');
    return $f;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文