在 PHP 7.4 中重写递归匿名函数

问题描述 投票:0回答:4

有如下匿名递归函数:

$f = function($n) use (&$f) {
    return ($n == 1) ? 1 : $n * $f($n - 1);
};

echo $f(5); // 120

我尝试重写到7.4版本,但出现错误,请告诉我我缺少了什么?

$f = fn($n) => ($n == 1) ? 1 : $n * $f($n - 1);
echo $f(5);

注意:未定义的变量:f

致命错误:未捕获错误:函数名称必须是字符串

php closures anonymous-function arrow-functions php-7.4
4个回答
16
投票

就像 Barmar 所说,你不能从外部范围使用

$f
,因为当隐式绑定发生时
$f
仍然是未定义的。

没有什么可以阻止您稍后将其作为参数传递。

$f = fn($f, $n) => $n == 1 ? 1 : $n * $f($f, $n - 1);
echo $f($f, 5); // 120

箭头函数的工作方式是,在定义期间,它们将使用外部作用域变量的按值绑定。

正如已经提到的,箭头函数使用按值变量绑定。这大致相当于对箭头函数内使用的每个变量

use($x)
执行
$x
。 - https://wiki.php.net/rfc/arrow_functions_v2

闭包对变量

$f
的赋值发生在闭包定义之后,并且变量
$f
在其之前未定义。

据我所知,在定义箭头函数时没有任何通过引用绑定的机制。


4
投票

我认为你不能将函数重写为箭头函数。

箭头函数将在创建函数时按值捕获任何外部变量的值。但是

$f
在创建函数并分配变量之前不会有值。

最初的匿名函数通过使用

use (&$f)
(而不是
use ($f)
)捕获对变量的引用来解决这个问题。这样,它将能够使用由赋值产生的变量的更新值。


2
投票

我想我刚刚找到了

$GLOBALS

的合法(不是?)用途之一
$f = fn ($n) =>($n == 1) ? 1 : $n * $GLOBALS['f']($n - 1);
echo $f(5); // 120

旁注:如果

$n < 1
怎么办?


2
投票

与 @scorpion35 所说的略有不同,你也可以应用柯里化:

$f = fn($f) => fn($x) => $x <= 1 
    ? $x 
    : $f($f)($x-1) * $x;
    
$factorial = $f($f);

$factorial(7); //5040
© www.soinside.com 2019 - 2024. All rights reserved.