ZetCode

PHP Arrow Functions

last modified May 21, 2025

This tutorial dives into PHP arrow functions, also known as short closures, introduced in PHP 7.4 to simplify function syntax.

Arrow functions provide a concise and readable way to define anonymous functions, eliminating the need for explicit use statements when capturing variables from the parent scope. They enhance code clarity and improve maintainability, making them ideal for simple callbacks, array manipulations, and inline operations.

Arrow functions are particularly useful in functional programming paradigms, where functions are treated as first-class citizens. They allow for cleaner and more expressive code, especially when used with array functions like array_map, array_filter, and usort.

The following table summarizes the key differences between arrow functions and regular closures in PHP.

Feature Arrow Functions Regular Closures
Variable Capture Automatically captures variables by value. Requires explicit use to capture external variables.
Return Behavior Implicit return (evaluates and returns the expression). Requires explicit return statement.
Multi-Statement Support Not supported; only single expressions. Fully supports multi-statement blocks inside {}.
Modification of Captured Variables Cannot modify captured variables. Allows modification when passed by reference (use (&$var)).
$this Binding Preserves $this from the declaring scope. $this can be rebound using bindTo.
Scope Control Uses static lexical scope; cannot be rebound. Allows dynamic scope rebinding.

This table summarizes the key differences between arrow functions and regular closures in PHP. Arrow functions are designed for simplicity and conciseness, making them ideal for straightforward use cases. Regular closures offer more flexibility and control, especially for complex logic and multi-statement functions.

Basic arrow function syntax

Arrow functions use the fn keyword instead of function and have a simplified syntax. They automatically inherit variables from the parent scope without needing the use keyword. The return is implicit for single expressions.

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";

This shows the basic syntax of arrow functions compared to traditional closures. Arrow functions automatically capture $factor from the parent scope. PHP 8.1 added support for multi-statement arrow functions with explicit returns.

λ php basic_arrow.php
8
8
50
Hello there!

Variable inheritance

Arrow functions automatically inherit variables from the parent scope by value (not by reference). This differs from traditional closures which require explicit use statements to capture variables.

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";

This demonstrates how arrow functions inherit variables. Scalar values are captured by value at function creation, while objects are captured by reference. Unlike regular closures, arrow functions cannot modify inherited variables.

λ php variable_inheritance.php
User_100
User_100
User_100
User_100
Alice
0

Common use cases

Arrow functions are particularly useful for array operations, callbacks, and simple transformations where their concise syntax improves readability.

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";

These examples show typical scenarios where arrow functions shine. They're especially useful with array functions like array_map and array_filter. The concise syntax makes callback-heavy code more readable.

Advanced usage patterns

Arrow functions can be used in more advanced patterns like currying, function composition, and as method return values. These patterns benefit from their concise syntax.

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

These advanced patterns demonstrate the power of arrow functions in functional programming styles. The concise syntax makes function composition and higher-order functions more readable. Note that recursive arrow functions require PHP 8.1+ and a reference to themselves.

λ 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 arrow functions provide a concise syntax for writing closures with automatic variable capture from the parent scope. Key points to remember:

In this article, we explored the syntax and usage of PHP arrow functions. We covered their differences from traditional closures, common use cases, and advanced patterns.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all PHP tutorials.