lambda 函数和闭包(在 PHP 中)之间的区别?

Posted

技术标签:

【中文标题】lambda 函数和闭包(在 PHP 中)之间的区别?【英文标题】:Difference between a lambda function and a closure (in PHP)? 【发布时间】:2013-11-24 17:16:15 【问题描述】:

“Magento php 开发人员指南”第 2 章指出:

Zend Framework 2 使用 100% 面向对象的代码并利用大部分 PHP 5.3 的新特性,即命名空间、后期静态绑定、 lambda 函数和闭包。

虽然What is the difference between a 'closure' and a 'lambda'? 的帖子有一些答案(例如,lambda 只是一个匿名函数,而闭包是一个可以访问不在其参数列表中的变量的函数),但似乎特定于 Python编程语言(其中提到了 Scheme 编程语言)。 例如,根据帖子,在 Python 中,似乎可以有不是 lambda 的闭包,也可以有不是闭包的 lambda。

但是,我对 PHP 编程语言感兴趣,而不是 Python。下面的答案之一似乎指出,在 PHP 中,所有闭包都是 lambda,这与与 Python 状态相关的帖子相冲突。

在我看来,这些概念的细节因语言而异,我对 PHP 很感兴趣,因此发了这篇文章。

所有这些都令人困惑。虽然我认为 lambda 函数通常只是未命名的函数,但以下 Wikipedia 文章更多地介绍了闭包:

http://en.wikipedia.org/wiki/Closure_%28computer_science%29

虽然在 PHP 中没有示例。

【问题讨论】:

你可以先搜索再问;这是同样的问题:***.com/questions/220658/… 以下来自 Philip Brown 的 article 很好地总结了 closurelambda 函数之间的区别。还提供了很好的例子。 【参考方案1】:

闭包是 php 中的一个 lambda 函数,它封装了变量,因此一旦它们的原始引用超出范围,就可以使用它们。

闭包是 lambda 函数,但 lambda 函数不是闭包,除非您指定 use 关键字。

这是一个更好的答案:https://***.com/a/220728/1152375

【讨论】:

谢谢。我发现有一个通用的答案。在那个线程中写的是 lambda 函数只是一个匿名函数,而闭包是访问可以在函数外部找到的变量的任何函数(这与您上面的答案不匹配,即每个闭包都是一个 lambda 函数,因为根据前面提到的线程,闭包可以有一个名称,只要它访问全局范围)。 这对 PHP 是否正确?我想每种语言都以稍微不同的方式定义这些概念,而我的问题是针对 PHP 的。 PHP中这些的确切定义是什么?谢谢。 @JohnSonderson:“闭包”和“匿名函数”的概念与语言无关 @newacct 概念和实现可以是两个不同的东西。例如PHP函数不能自动访问全局作用域的环境,PHP手册在php.net/manual/en/class.closure.php的第一行专门定义闭包对象类型为“匿名函数” PHP 实现闭包的另一个重要区别是,默认情况下提供给函数的环境不是由引用变量构成的。 wiki.php.net/rfc/closures#references_vs_copies【参考方案2】:

有一篇PHP专用的文章有详细的解释和代码示例: http://www.ibm.com/developerworks/library/os-php-5.3new2/

断开链接警告:截至 2014 年 10 月 18 日,上述链接为 404。 我从谷歌缓存中复制了这篇文章并放在here:

如果您发现原始文档在任何地方重新出现,请告诉我。

【讨论】:

文章原链接又出现了。【参考方案3】:

闭包实际上意味着如果你use一个变量,它的值将在一个封闭的函数内使用,而不是在它之外更新它的值。如果您想更新已使用变量的值但作为普通参数,则必须使用引用运算符 &

这就是它的强大用途,您可以在没有依赖全局命名空间的常规函数​​的情况下更轻松地增加/递减类似的东西或创建斐波那契或迭代生成器函数。

Lambda 不支持use,因此它们不能包含外部范围的变量。闭包也可以被缓存,因此它提高了编译性能。

【讨论】:

【参考方案4】:

Lambda 函数被分配给一个变量或作为参数传递给另一个函数。闭包使用范围之外的变量。

使用 lambdas

因为函数没有名字,你不能像普通函数那样调用它。相反,您必须将其分配给变量或将其作为参数传递给另一个函数。

// Anonymous function
// assigned to variable
$greeting = function () 
  return "Hello world";


// Call function
echo $greeting();
// Returns "Hello world"

为了使用匿名函数,我们将它分配给一个变量,然后将该变量作为函数调用。

您也可以将函数传递给另一个函数,如下所示:

// Pass Lambda to function
function shout ($message)
  echo $message();


// Call function
shout(function()
  return "Hello world";
);

什么是闭包?

闭包本质上与 Lambda 相同,只是它可以访问其创建范围之外的变量。

例如:

// Create a user
$user = "Philip";

// Create a Closure
$greeting = function() use ($user) 
  echo "Hello $user";
;

// Greet the user
$greeting(); // Returns "Hello Philip"

正如您在上面看到的,闭包能够访问$user 变量,因为它是在闭包函数定义的 use 子句中声明的。

如果您要更改闭包中的$user 变量,它不会影响原始变量。要更新原始变量,我们可以附加一个 & 符号。变量前的 & 表示这是一个引用,因此也会更新原始变量。

For example:
// Set counter
$i = 0;
// Increase counter within the scope
// of the function
$closure = function () use ($i) $i++; ;
// Run the function
$closure();
// The global count hasn't changed
echo $i; // Returns 0

// Reset count
$i = 0;
// Increase counter within the scope
// of the function but pass it as a reference
$closure = function () use (&$i) $i++; ;
// Run the function
$closure();
// The global count has increased
echo $i; // Returns 1

本文是 Philip Brown 文章的一部分,位于 >> culttt.com。您可以在此处找到更多示例。

【讨论】:

【参考方案5】:

功能

一段代码以参数的形式接受一个或多个输入,进行一些处理并返回一个值。 它应该有一个名字,需要时可以用它的名字来调用。 可以将多个函数包装在一个类中(以允许拥有多个同名的函数等等)。

匿名函数

一个没有名字的函数。 不一定需要创建闭包。

Lambda

可以分配给变量或作为参数传递给其他函数的匿名函数。 它不能像普通函数一样被调用,因为它没有名称,它必须要么将它分配给一个变量,要么将它作为参数传递给另一个函数。因此它变成了一个 Lambda 函数。 它很有用,因为它们是一种一次性功能,您可以只在某个地方使用一次,而无需在许多地方重复使用它。

关闭

与 Lambda 相同。但它可以在不使用全局变量的情况下从外部范围访问变量。 (它可以捕捉周围环境的状态)。 可以使用“use”语法以简洁的方式解决变量范围限制。 (基本上它是一个使用 use 语法的匿名函数)。 它不仅是为匿名函数创建的。

它比 Lambda 更智能,因为它能够与来自外部环境的变量进行交互。

    

【讨论】:

以上是关于lambda 函数和闭包(在 PHP 中)之间的区别?的主要内容,如果未能解决你的问题,请参考以下文章

从λ演算到函数式编程聊闭包:闭包概念在Java/PHP/JS中形式

C# 闭包中的 Lambda 表达式是啥?

C# 闭包中的 Lambda 表达式是啥?

Java中Lambda表达式和Groovy闭包的相关解析

lambda表达式和闭包

lambda 函数闭包捕获啥?