PHP 箭头函数
最后修改于 2025 年 5 月 21 日
本教程深入探讨了 PHP 箭头函数,也称为短闭包,在 PHP 7.4 中引入,以简化函数语法。
箭头函数提供了一种简洁易读的方式来定义匿名函数,无需在捕获来自父作用域的变量时使用显式的 use 语句。它们增强了代码清晰度并提高了可维护性,非常适合简单的回调、数组操作和内联操作。
箭头函数在函数式编程范例中特别有用,其中函数被视为一等公民。它们允许更清晰、更具表现力的代码,尤其是在与 array_map、array_filter 和 usort 等数组函数一起使用时。
下表总结了 PHP 中箭头函数和常规闭包之间的主要区别。
| 功能 | 箭头函数 | 常规闭包 |
|---|---|---|
| 变量捕获 | 通过值自动捕获变量。 | 需要显式的 use 来捕获外部变量。 |
| 返回行为 | 隐式返回(计算并返回表达式)。 | 需要显式的 return 语句。 |
| 多语句支持 | 不支持;仅支持单个表达式。 | 完全支持 {} 内的多语句块。 |
| 修改捕获的变量 | 无法修改捕获的变量。 | 允许通过引用传递时进行修改(使用 (&$var))。 |
$this 绑定 |
保留来自声明作用域的 $this。 |
可以使用 bindTo 重新绑定 $this。 |
| 作用域控制 | 使用静态词法作用域;无法重新绑定。 | 允许动态作用域重新绑定。 |
该表总结了 PHP 中箭头函数和常规闭包之间的主要区别。箭头函数专为简单性和简洁性而设计,使其非常适合直接用例。常规闭包提供更大的灵活性和控制力,尤其适用于复杂的逻辑和多语句函数。
基本箭头函数语法
箭头函数使用 fn 关键字而不是 function,并具有简化的语法。它们自动从父作用域继承变量,而无需使用 use 关键字。对于单个表达式,返回是隐式的。
<?php
declare(strict_types=1);
// Traditional closure
$addOld = function($a, $b) {
return $a + $b;
};
// Arrow function equivalent
$addNew = fn($a, $b) => $a + $b;
echo $addOld(5, 3) . "\n"; // 8
echo $addNew(5, 3) . "\n"; // 8
// Automatic variable capture
$factor = 10;
$multiplier = fn($x) => $x * $factor;
echo $multiplier(5) . "\n"; // 50
// Type declarations (PHP 8.0+)
$concat = fn(string $a, string $b): string => $a . $b;
echo $concat("Hello ", "there!") . "\n";
这显示了箭头函数与传统闭包的基本语法比较。箭头函数自动从父作用域捕获 $factor。PHP 8.1 增加了对具有显式返回的多语句箭头函数的支持。
λ php basic_arrow.php 8 8 50 Hello there!
变量继承
箭头函数通过值(而不是引用)自动从父作用域继承变量。这与需要显式 use 语句来捕获变量的传统闭包不同。
<?php
declare(strict_types=1);
$prefix = "User_";
$id = 100;
// Traditional closure with use
$oldFormat = function() use ($prefix, $id) {
return $prefix . $id;
};
// Arrow function automatically captures
$newFormat = fn() => $prefix . $id;
echo $oldFormat() . "\n"; // User_100
echo $newFormat() . "\n"; // User_100
// Variables are captured by value
$id = 200;
echo $oldFormat() . "\n"; // Still User_100
echo $newFormat() . "\n"; // Still User_100
// Objects are captured by reference
$user = new class {
public string $name = 'John';
};
$getName = fn() => $user->name;
$user->name = 'Alice';
echo $getName() . "\n"; // Alice (reference)
// Cannot modify captured variables
$counter = 0;
$increment = fn() => $counter++; // Cannot modify counter
echo $increment() . "\n";
这演示了箭头函数如何继承变量。标量值在函数创建时通过值捕获,而对象通过引用捕获。与常规闭包不同,箭头函数无法修改继承的变量。
λ php variable_inheritance.php User_100 User_100 User_100 User_100 Alice 0
常见用例
箭头函数特别适用于数组操作、回调和简单的转换,其简洁的语法提高了可读性。
<?php
declare(strict_types=1);
// Array operations
$numbers = [1, 2, 3, 4, 5];
$squared = array_map(fn($n) => $n ** 2, $numbers);
print_r($squared);
// Filtering
$even = array_filter($numbers, fn($n) => $n % 2 === 0);
print_r($even);
// Sorting
$users = [
['name' => 'Alice', 'age' => 25],
['name' => 'Bob', 'age' => 30],
['name' => 'Charlie', 'age' => 20]
];
usort($users, fn($a, $b) => $a['age'] <=> $b['age']);
print_r($users);
// Callbacks
$greet = function(string $name, callable $formatter) {
echo $formatter($name) . "\n";
};
$greet('John', fn($n) => "Hello, $n!");
// Object method callbacks
class Calculator {
public function calculate(array $values, callable $operation): array {
return array_map($operation, $values);
}
}
$calc = new Calculator();
$result = $calc->calculate([1, 2, 3], fn($x) => $x * 10);
print_r($result);
// Immediately invoked function expression (IIFE)
$result = (fn($x, $y) => $x + $y)(5, 3);
echo "IIFE result: $result\n";
这些示例展示了箭头函数大放异彩的典型场景。它们尤其适用于 array_map 和 array_filter 等数组函数。简洁的语法使回调密集型代码更具可读性。
高级用法模式
箭头函数可用于更高级的模式,如柯里化、函数组合和作为方法返回值。这些模式受益于其简洁的语法。
<?php
declare(strict_types=1);
// 1. Currying with Arrow Functions
function multiply(float $a): callable {
return fn(float $b) => $a * $b;
}
$double = multiply(2);
$triple = multiply(3);
echo "Double: " . $double(5) . "\n"; // 10
echo "Triple: " . $triple(5) . "\n"; // 15
// 2. Function Composition
function compose(callable ...$functions): callable {
return fn($x) => array_reduce(
array_reverse($functions),
fn($carry, $f) => $f($carry),
$x
);
}
$addOne = fn($x) => $x + 1;
$square = fn($x) => $x * $x;
$addThenSquare = compose($square, $addOne);
echo "Composed function result: " . $addThenSquare(3) . "\n"; // (3 + 1)^2 = 16
// 3. Factory Pattern with Arrow Functions
class OperationFactory {
public static function create(string $type): callable {
return match($type) {
'add' => fn($a, $b) => $a + $b,
'sub' => fn($a, $b) => $a - $b,
'mul' => fn($a, $b) => $a * $b,
'div' => fn($a, $b) => $b != 0 ? $a / $b : throw new InvalidArgumentException("Cannot divide by zero"),
default => throw new InvalidArgumentException("Unknown operation"),
};
}
}
$adder = OperationFactory::create('add');
echo "Factory pattern (Addition): " . $adder(10, 5) . "\n"; // 15
// 4. Logging with Arrow Functions
function createLogger(string $prefix): callable {
return fn(string $message) => "[$prefix] $message\n";
}
$errorLogger = createLogger('ERROR');
$infoLogger = createLogger('INFO');
echo $errorLogger('Something went wrong');
echo $infoLogger('Process completed');
// 5. Recursive Arrow Functions (PHP 8.1+)
$factorial = function(int $n) use (&$factorial): int {
return $n <= 1 ? 1 : $n * $factorial($n - 1);
};
echo "Factorial of 5: " . $factorial(5) . "\n"; // 120
这些高级模式展示了箭头函数在函数式编程风格中的强大功能。简洁的语法使函数组合和高阶函数更具可读性。请注意,递归箭头函数需要 PHP 8.1+ 和对自身的引用。
λ php advanced_patterns.php Double: 10 Triple: 15 Composed function result: 16 Factory pattern (Addition): 15 [ERROR] Something went wrong [INFO] Process completed Factorial of 5: 120
PHP 箭头函数提供了一种简洁的语法,用于编写闭包,并从父作用域自动捕获变量。需要记住的关键点
- 在 PHP 7.4 中引入,使用
fn关键字和=>语法。 - 自动捕获变量 通过值从父作用域。
- 隐式返回 用于单表达式函数。
- 无法修改捕获的变量 或使用按引用传递的参数。
- 在类上下文中保持原始的
$this绑定。 - 最适合简单的回调和数组操作,因为其简洁的语法。
- 与传统闭包相比,有更多限制。
- 在 PHP 8.1 中改进,支持多语句以提高灵活性。
在本文中,我们探讨了 PHP 箭头函数的语法和用法。我们介绍了它们与传统闭包的区别、常见用例和高级模式。
作者
列出 所有 PHP 教程。