ZetCode

PHP 箭头函数

最后修改于 2025 年 5 月 21 日

本教程深入探讨了 PHP 箭头函数,也称为短闭包,在 PHP 7.4 中引入,以简化函数语法。

箭头函数提供了一种简洁易读的方式来定义匿名函数,无需在捕获来自父作用域的变量时使用显式的 use 语句。它们增强了代码清晰度并提高了可维护性,非常适合简单的回调、数组操作和内联操作。

箭头函数在函数式编程范例中特别有用,其中函数被视为一等公民。它们允许更清晰、更具表现力的代码,尤其是在与 array_maparray_filterusort 等数组函数一起使用时。

下表总结了 PHP 中箭头函数和常规闭包之间的主要区别。

功能 箭头函数 常规闭包
变量捕获 通过值自动捕获变量。 需要显式的 use 来捕获外部变量。
返回行为 隐式返回(计算并返回表达式)。 需要显式的 return 语句。
多语句支持 不支持;仅支持单个表达式。 完全支持 {} 内的多语句块。
修改捕获的变量 无法修改捕获的变量。 允许通过引用传递时进行修改(使用 (&$var))。
$this 绑定 保留来自声明作用域的 $this 可以使用 bindTo 重新绑定 $this
作用域控制 使用静态词法作用域;无法重新绑定。 允许动态作用域重新绑定。

该表总结了 PHP 中箭头函数和常规闭包之间的主要区别。箭头函数专为简单性和简洁性而设计,使其非常适合直接用例。常规闭包提供更大的灵活性和控制力,尤其适用于复杂的逻辑和多语句函数。

基本箭头函数语法

箭头函数使用 fn 关键字而不是 function,并具有简化的语法。它们自动从父作用域继承变量,而无需使用 use 关键字。对于单个表达式,返回是隐式的。

basic_arrow.php
<?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 语句来捕获变量的传统闭包不同。

variable_inheritance.php
<?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

常见用例

箭头函数特别适用于数组操作、回调和简单的转换,其简洁的语法提高了可读性。

use_cases.php
<?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_maparray_filter 等数组函数。简洁的语法使回调密集型代码更具可读性。

高级用法模式

箭头函数可用于更高级的模式,如柯里化、函数组合和作为方法返回值。这些模式受益于其简洁的语法。

advanced_patterns.php
<?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 箭头函数的语法和用法。我们介绍了它们与传统闭包的区别、常见用例和高级模式。

作者

我叫 Jan Bodnar,是一位充满激情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。迄今为止,我撰写了 1,400 多篇文章和 8 本电子书。我拥有超过十年的编程教学经验。

列出 所有 PHP 教程