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 教程。