Arrow Functions
PHP 5.3 has introduced anonymous functions and closures, allowing us to define a function in-place, and thus write code that has no external dependencies. This comes in handy with comparison functions, for example.
Especially when they only perform a simple operation, anonymous functions in PHP can be perceived as rather verbose when compared to other programming languages. Consider the following example:
function array_values_from_keys(array $array, array $keys): array
{
return array_map(
function (string $x) use ($array)
{
return $array[$x];
},
$keys
);
}
$array = ['a' => 1, 'b' => 2, 'c' => 3];
$keys = ['a', 'c'];
var_dump(array_values_from_keys($array, $keys));
Executing the code shown above will print the output shown below:
array(2) {
[0]=>
int(1)
[1]=>
int(3)
}
The closure’s actual operation, return $array[$x]
,
gets lost between the required boilerplate code. The example shown
below accomplishes the same as the one shown above – but with less
code:
function array_values_from_keys(array $array, array $keys): array
{
return array_map(
fn(string $x) => $array[$x],
$keys
);
}
The new fn
keyword is used to declare a so-called
arrow function. These provide a more concise syntax to express
closures.
fn(parameter list) => expression
When a variable used in the expression is defined in the parent scope it will be implicitly captured by-value. Implicitly captured variables follow the same scoping rules as regular function arguments. This means that you can safely modify them locally.
$y = 1;
$f = fn(int $x): int => $x + $y;
The arrow function shown above is equivalent to the closure shown below:
$y = 1;
$f = function (int $x) use ($y) { return $x + $y; };
If you look closely, you will notice that
fn(int $x): int
has a return type declaration and
function (int $x) use ($y)
does not. This is another
advantage of arrow functions over regular closures as
function (int $x): int use ($y)
is not possible and
results in a compiler error.
Arrow functions may be nested:
$z = 1;
$fn = fn(int $x) => fn(int $y): int => $x * $y + $z;
In the example shown above, the outer arrow function captures
$z
from the parent scope. The inner arrow function then
also captures $z
from the outer function’s scope. Thus
the value of $z
from the parent scope becomes available
in the inner arrow function.
The syntax for arrow function allows type declarations for parameters and return values, default values, variadics, as well as by-reference passing and returning. The examples shown below are all valid:
fn(int $x) => $x;
fn(): int => $x;
fn(int $x = 42) => $x;
fn(&$x) => $x;
fn&($x) => $x;
fn($x, ...$rest) => $rest;
$this
is automatically bound when an arrow function
is created inside a class method. Just like with regular closures,
the static
keyword can be used to prevent this:
class C
{
public function m(): void
{
$f = fn() => var_dump($this);
$f();
$f = static fn() => var_dump($this);
$f();
}
}
Executing the code shown above will print the output shown below:
object(C)#1 (0) {
}
PHP Fatal error: Uncaught Error: Using $this when not in object context in ...
Because the first arrow function was declared with just
fn
the $this
variable is bound and can be
accessed. The second arrow function is declared with
static fn
, the $this
variable is therefore
not bound and not available. This is why accessing it leads to an
error.