Arrow Functions (fn)
| Since: | PHP 7.0(2015) |
|---|
Arrow functions (the『fn』keyword), added in『PHP』7.4, provide a concise syntax for short anonymous functions. Unlike closures written with the『function』keyword, they automatically capture variables from the outer scope without requiring『use』, making callback code cleaner and more compact.
Syntax
// Basic arrow function syntax
$functionName = fn(arg) => expression;
// No arguments
$functionName = fn() => expression;
// With type hints and return type
$functionName = fn(type $arg): returnType => expression;
// Traditional closure (for comparison)
$closure = function(arg) use ($outerVar) {
return expression;
};
Differences Between Arrow Functions and Closures
| Item | Closure (function) | Arrow Function (fn) |
|---|---|---|
| Capturing outer variables | Must be explicitly declared with『use ($var)』. | Automatically captures variables from the outer scope. No『use』required. |
| Capture type | By value (default) or by reference (&) can be chosen. | By value only. Capture by reference is not possible. |
| Body syntax | Multiple statements can be written inside『{ }』. | A single expression only.『return』is not written (returned automatically). |
| Multi-line processing | Supported. Complex logic can be written. | Not supported. Not suitable when processing cannot fit in a single expression. |
| Use cases | Suited for complex processing or side-effect-producing operations. | Suited for simple value-returning operations such as transformations and filters. |
Sample Code
Arrow Function Basics and Automatic Outer Variable Capture
arrow_basic.php
<?php
// Basic arrow function example using Steins;Gate character names
// ---- Closure (use required) ----
$labName = "Future Gadget Laboratory";
// In a closure, the outer variable $labName must be explicitly captured with use
$greetClosure = function(string $name) use ($labName): string {
return $name . " is a member of " . $labName . ".";
};
echo $greetClosure("岡部倫太郎") . "\n";
echo $greetClosure("椎名まゆり") . "\n";
// ---- Arrow function (no use required) ----
// Arrow functions automatically capture outer variables
// $labName can be referenced directly without use
$greetArrow = fn(string $name): string => $name . " is a member of " . $labName . ".";
echo $greetArrow("阿万音鈴羽") . "\n";
echo $greetArrow("桐生萌郁") . "\n";
Running the code produces the following output:
php arrow_basic.php 岡部倫太郎 is a member of Future Gadget Laboratory. 椎名まゆり is a member of Future Gadget Laboratory. 阿万音鈴羽 is a member of Future Gadget Laboratory. 桐生萌郁 is a member of Future Gadget Laboratory.
Combining with array_map / array_filter
arrow_array_map_filter.php
<?php
// Example combining array_map / array_filter with arrow functions
// using Steins;Gate character data
$characters = [
["name" => "岡部倫太郎", "divergence" => 1.048596, "isMember" => true],
["name" => "牧瀬紅莉栖", "divergence" => 1.130205, "isMember" => true],
["name" => "椎名まゆり", "divergence" => 1.048596, "isMember" => true],
["name" => "阿万音鈴羽", "divergence" => 1.048596, "isMember" => true],
["name" => "ビルゲイツ10世", "divergence" => 0.337187, "isMember" => false],
];
// array_map: build an array of labeled strings for each character
// Each element is transformed using an arrow function
$labels = array_map(
fn($c) => $c["name"] . " (divergence: " . $c["divergence"] . ")",
$characters
);
echo "--- All Characters ---\n";
foreach ($labels as $label) {
echo $label . "\n";
}
// array_filter: extract only lab members
// The filter condition is specified with an arrow function
$members = array_filter(
$characters,
fn($c) => $c["isMember"] === true
);
echo "\n--- Lab Members Only ---\n";
foreach ($members as $member) {
echo $member["name"] . "\n";
}
// Example of automatic outer variable capture
// Extract only characters on a specific world line
$targetDivergence = 1.048596;
$filtered = array_filter(
$characters,
// The arrow function can reference $targetDivergence without use
fn($c) => $c["divergence"] === $targetDivergence
);
echo "\n--- Characters on world line " . $targetDivergence . " ---\n";
foreach ($filtered as $c) {
echo $c["name"] . "\n";
}
Running the code produces the following output:
php arrow_array_map_filter.php --- All Characters --- 岡部倫太郎 (divergence: 1.048596) 牧瀬紅莉栖 (divergence: 1.130205) 椎名まゆり (divergence: 1.048596) 阿万音鈴羽 (divergence: 1.048596) ビルゲイツ10世 (divergence: 0.337187) --- Lab Members Only --- 岡部倫太郎 牧瀬紅莉栖 椎名まゆり 阿万音鈴羽 --- Characters on world line 1.048596 --- 岡部倫太郎 椎名まゆり 阿万音鈴羽
Nested Arrow Functions and Multi-level Outer Variable Capture
arrow_nested.php
<?php
// Nested arrow functions also automatically capture variables from outer scopes
// With closures, each level of nesting requires its own use declaration
$worldLine = "Beta world line";
$organization = "SERN";
// The outer arrow function captures $worldLine,
// and the inner arrow function captures both $worldLine and $organization
$getInfo = fn(string $name) =>
fn(int $labMemNo): string =>
"Lab Member No." . $labMemNo . " " . $name
. " (" . $worldLine . " / " . $organization . ")";
// Call the outer function first, then the inner function
$okabeInfo = $getInfo("岡部倫太郎");
echo $okabeInfo(1) . "\n";
$kurisu = $getInfo("牧瀬紅莉栖");
echo $kurisu(4) . "\n";
// Comparison: the same logic written with closures requires double use declarations
$getInfoClosure = function(string $name) use ($worldLine, $organization) {
return function(int $labMemNo) use ($name, $worldLine, $organization): string {
return "Lab Member No." . $labMemNo . " " . $name
. " (" . $worldLine . " / " . $organization . ")";
};
};
$mayuri = $getInfoClosure("椎名まゆり");
echo $mayuri(2) . "\n";
Running the code produces the following output:
php arrow_nested.php Lab Member No.1 岡部倫太郎 (Beta world line / SERN) Lab Member No.4 牧瀬紅莉栖 (Beta world line / SERN) Lab Member No.2 椎名まゆり (Beta world line / SERN)
Applicable Situations and Limitations
| Item | Details |
|---|---|
| Suitable use cases | Suited as callback arguments for functions like『array_map』,『array_filter』,『array_reduce』, and『usort』, where values are transformed, extracted, or compared simply. |
| Single-expression restriction | The body can only contain a single expression. Use a closure when multiple statements or conditional branching is required. |
| No reference capture | Outer variables are captured by value only. Modifying an outer variable from inside the arrow function is not possible. Use a closure with『use (&$var)』when modification is needed. |
| Not suited for recursion | Recursive calls via a named variable are technically possible but reduce readability. Use a regular named function for recursive logic. |
| Return value | The result of the expression is returned automatically. An explicit『return』is not written (writing one causes a syntax error). |
| PHP version | Available in PHP 7.4 and later. Not supported in PHP 7.3 or earlier. |
Common Mistakes
Writing multiple statements in the arrow function body
The body of an arrow function can only contain a single expression. Trying to write multiple statements causes a syntax error.
ng_arrow_multi.php
<?php
$labName = "Future Gadget Laboratory";
// Trying to write multiple statements in the arrow function body (syntax error)
$greet = fn(string $name) => {
$label = $name . " is a member of " . $labName . ".";
return $label;
};
Running the code produces the following output:
php ng_arrow_multi.php
Parse error: syntax error, unexpected token "{" in ng_arrow_multi.php on line 5
When multiple statements are needed, use a closure with the function keyword.
ok_arrow_multi.php
<?php
$labName = "Future Gadget Laboratory";
// Use a closure when multiple statements are needed
$greet = function(string $name) use ($labName): string {
$label = $name . " is a member of " . $labName . ".";
return $label;
};
echo $greet("岡部倫太郎") . "\n";
echo $greet("椎名まゆり") . "\n";
Running the code produces the following output:
php ok_arrow_multi.php 岡部倫太郎 is a member of Future Gadget Laboratory. 椎名まゆり is a member of Future Gadget Laboratory.
Writing return in the arrow function body
In arrow functions, the result of the expression is returned automatically. Writing an explicit return causes a syntax error.
ng_arrow_return.php
<?php $members = ["岡部倫太郎", "牧瀬紅莉栖", "阿万音鈴羽"]; // Writing return causes a syntax error $upper = array_map(fn($name) => return strtoupper($name), $members);
Running the code produces the following output:
php ng_arrow_return.php Parse error: syntax error, unexpected token "return" in ng_arrow_return.php on line 5
Write only an expression in the arrow function body. return is not needed.
ok_arrow_return.php
<?php
$divergences = [1.048596, 1.130205, 0.337187];
// No return needed. Write the expression directly
$rounded = array_map(fn($d) => round($d, 2), $divergences);
foreach ($rounded as $v) {
echo $v . "\n";
}
Running the code produces the following output:
php ok_arrow_return.php 1.05 1.13 0.34
Trying to modify an outer variable from inside an arrow function
Arrow functions capture outer variables by value. Attempting to increment a counter or otherwise modify an outer variable inside an arrow function has no effect on the original variable.
ng_arrow_modify.php
<?php $count = 0; $members = ["岡部倫太郎", "牧瀬紅莉栖", "椎名まゆり"]; // Trying to modify $count inside the arrow function, but it is not reflected array_walk($members, fn($name) => $count++); echo $count . "\n"; // stays 0
Running the code produces the following output:
php ng_arrow_modify.php 0
To modify an outer variable, use a closure with use (&$var) for reference capture.
ok_arrow_modify.php
<?php
$count = 0;
$members = ["岡部倫太郎", "牧瀬紅莉栖", "椎名まゆり"];
// Use a closure with reference capture to modify the outer variable
array_walk($members, function($name) use (&$count) {
$count++;
});
echo $count . "\n"; // 3
Running the code produces the following output:
php ok_arrow_modify.php 3
Summary
Arrow functions (the『fn』keyword) are a shorthand syntax added in PHP 7.4. Their defining feature is the ability to automatically capture variables from the outer scope without『use』.However, the body is limited to a single expression, and capture by reference is not possible.These restrictions mean that complex logic or operations with side effects still require traditional closures.
When using arrow functions as callbacks for『array_map』or『array_filter』, outer variables can be referenced naturally, keeping the code concise. Nested arrow functions also capture variables from each scope automatically, eliminating the need for multiple levels of『use』declarations as would be required with closures. For details on『array_map』and『array_filter』, see『array_map / array_filter』.
Both arrow functions and closures are function objects that can be assigned to variables or passed as arguments. Arrow functions are appropriate when the logic is short and simply returns a value; closures are appropriate when multiple statements are needed or when an outer variable must be modified. For details on closures, see『Anonymous Functions (Closures)』.
If you find any errors or copyright issues, please contact us.