与匿名函数不同,箭头函数不能有 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($x): 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 时才有可能。
在示例 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(预期结果)
但是在这里,它不会自动获取父作用域中的值,我们必须显式传递它们。
如您所知,变量绑定在箭头函数中按“按值”进行。这意味着,箭头函数返回在其内部使用的变量从外部作用域的值的副本。
现在让我们看一个箭头函数返回引用而不是值副本的示例。
<?php
$x = 0;
$fn = fn &(&$x) => $x; // 返回一个引用
$y = &$fn($x); // 现在 $y 代表该引用
var_dump($y); // 输出:0
$y = 3; // 更改 $y 的值会影响 $x
var_dump($x); // 输出:3
?>
注意 `compact()` 函数无法访问外部作用域的变量 (已知版本:7.4.0, 7.4.8) (bug: 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)
}
如果您是 JavaScript 开发人员,以下是与 JS 箭头函数的异同
相同点
- 创建一个匿名函数
- 将 “$this” 的值绑定到父作用域中的值。
- (以及父作用域的所有其他变量。请参见下面的注释)
不同点
- 你必须写 “fn()” 而不仅仅是 “()”
- 函数体仅限于一个表达式
- 所以没有使用 “{” 和 “}” 的多行函数体
相同点和不同点
- 绑定父作用域中的所有变量
- 在 JavaScript 中,所有函数都是闭包,绑定到其父作用域中的变量(除了 “this”)。
- 但在 PHP 中,普通匿名函数(用 “function() {}” 定义)无法访问父作用域,除非它们用关键字 “use” 显式声明闭包。
- 另一方面,PHP 箭头函数会自动绑定到父作用域中的所有变量。因此,这使它们的的行为与 JS 函数相同,但请注意,在 PHP 中,这是箭头函数特有的特殊行为。