与匿名函数不同,箭头函数不能有 void 返回类型声明。
可能看起来很明显,但如果您认为可以利用箭头函数的优势(使用来自父作用域的变量)来简化函数或方法调用,请记住,只有在您没有告诉 PHP 箭头函数确实返回 void 时才有可能。
箭头函数是在 PHP 7.4 中引入的,作为 匿名函数 的更简洁语法。
匿名函数和箭头函数都使用 Closure 类实现。
箭头函数的基本形式为 fn (argument_list) => expr
。
箭头函数支持与 匿名函数 相同的功能,只是始终自动使用来自父作用域的变量。
当在表达式中使用的变量在父作用域中定义时,它将被隐式按值捕获。在以下示例中,函数 $fn1 和 $fn2 的行为相同。
示例 #1 箭头函数自动按值捕获变量
<?php
$y = 1;
$fn1 = fn($x) => $x + $y;
// 等同于按值使用 $y:
$fn2 = function ($x) use ($y) {
return $x + $y;
};
var_export($fn1(3));
?>
上面的示例将输出
4
这在箭头函数嵌套时也适用
示例 #2 箭头函数自动按值捕获变量,即使嵌套时也是如此
<?php
$z = 1;
$fn = fn($x) => fn($y) => $x * $y + $z;
// 输出 51
var_export($fn(5)(10));
?>
与匿名函数类似,箭头函数语法允许任意函数签名,包括参数和返回类型、默认值、可变参数,以及按引用传递和返回。以下都是有效的箭头函数示例
示例 #3 箭头函数示例
<?php
fn(array $x) => $x;
static fn(): int => $x;
fn($x = 42) => $x;
fn(&$x) => $x;
fn&($x) => $x;
fn($x, ...$rest) => $rest;
?>
箭头函数使用按值变量绑定。这大致等同于对箭头函数内部使用的每个变量 $x 执行 use($x)
。按值绑定意味着无法修改外部作用域中的任何值。可以使用 匿名函数 来进行按引用绑定。
示例 #4 箭头函数无法修改来自外部作用域的值
<?php
$x = 1;
$fn = fn() => $x++; // 没有效果
$fn();
var_export($x); // 输出 1
?>
版本 | 描述 |
---|---|
7.4.0 | 箭头函数变得可用。 |
注意: 可以在箭头函数内部使用 func_num_args()、func_get_arg() 和 func_get_args()。
与匿名函数不同,箭头函数不能有 void 返回类型声明。
可能看起来很明显,但如果您认为可以利用箭头函数的优势(使用来自父作用域的变量)来简化函数或方法调用,请记住,只有在您没有告诉 PHP 箭头函数确实返回 void 时才有可能。
如您所知,变量绑定在箭头函数中是按“按值”进行的。这意味着,箭头函数返回在其中使用的变量的值的副本,而不是来自外部作用域的副本。
现在让我们看一个箭头函数返回引用而不是值副本的例子。
<?php
$x = 0;
$fn = fn &(&$x) => $x; // 返回引用
$y = &$fn($x); // 现在 $y 代表引用
var_dump($y); // 输出:0
$y = 3; // 更改 $y 的值会影响 $x
var_dump($x); // 输出:3
?>
在示例 4(箭头函数无法修改来自外部作用域的值)中
<?php
$x = 1;
$fn = fn() => $x++; // 没有效果
$fn();
var_export($x); // 输出 1
?>
在这里,我们可以在 fn(&$x) 中使用引用变量,并将值从函数调用 $fn($x) 传递过去,这样我们就可以通过不使用匿名函数来获得预期的输出。
示例
<?php
$x = 1;
$fn = fn(&$x) => $x++;
$fn($x);
var_export($x);
?>
输出:2(如预期)
但是这里它不会自动从父作用域中获取值,我们必须显式地传递它们。
注意 compact() 无法访问(导入)外部作用域中的变量(在版本 7.4.0、7.4.8 中已知)(错误:https://bugs.php.net/bug.php?id=78970)。
有一个解决方法 - 直接使用变量;这将导致它被导入到箭头函数的命名空间中,并使其可供 compact() 使用。
<?php
$aa = 111;
$accessing_variable_works = fn($bb) => [ $aa, $bb ];
$compact_is_broken = fn($bb) => compact('aa', 'bb');
$compact_can_work_with_workaround = fn($bb) => compact('aa', 'bb') + ['workaround' => $aa];
var_dump($accessing_variable_works(333));
var_dump($compact_is_broken(555));
var_dump($compact_can_work_with_workaround(777));
?>
结果
array(2) {
[0]=>
int(111)
[1]=>
int(333)
}
PHP Notice: compact(): Undefined variable: aa in /home/m/vlt/guitar/tlb/s/public_html/index.php on line 9
array(1) {
["bb"]=>
int(555)
}
array(3) {
["aa"]=>
int(111)
["bb"]=>
int(777)
["workaround"]=>
int(111)
}
<?php
$x = 1;
(fn() => print($x))(); // 输出 1
(fn($x) => print($x))(2); // 输出 2