If you enjoy reading my blog, you could consider supporting me on Patreon.

Short closures in PHP

Short closures, also called arrow functions, are a way of writing shorter functions in PHP. This notation is useful when passing closures to functions like array_map or array_filter.

This is what they look like:

// A collection of Post objects
$posts = [/* … */];

$ids = array_map(fn($post) => $post->id, $posts);

Previously, you'd had to write this:

$ids = array_map(function ($post) {
    return $post->id;
}, $posts);

Let's summarize how short closures can be used.

A more strictly typed way of writing the example above could be this:

$ids = array_map(fn(Post $post): int => $post->id, $posts);

Two more things to mention:

If you want to return a value by reference, the following syntax should be used:

fn&($x) => $x

In short, short closures allow the same functionality you'd expect from normal closures, with the exception of only allowing one expression.

# No multi-line

You read it right: short closures can only have one expression. This means you cannot have multiple lines in them.

The reasoning is as follows: the goal of short closures is to reduce verbosity. fn is of course shorter than function in all cases. Nikita Popov, the creator of the RFC, however argued that if you're dealing with multi-line functions, there is less to be gained by using short closures.

After all, multi-line closures are by definition already more verbose; so being able to skip two keywords (function and return) wouldn't make much of a difference.

Whether you agree with this sentiment is up to you. While I can think of many one-line closures in my projects, there are also plenty of multi-line ones, and I'll personally miss the short syntax in those cases.

There's hope though: it is possible to add multi-line short closures in the future, but that's an RFC on its own.

# Values from outer scope

Another significant difference between short and normal closures is that the short ones don't require the use keyword to be able to access data from the outer scope.

$modifier = 5;

array_map(fn($x) => $x * $modifier, $numbers);

It's important to note that you're not allowed to modify variables from the outer scope. Values are bound by value and not by reference. This means that you could change $modifier within the short closure, though it wouldn't have effect on the $modifier variable in the outer scope.

One exception is of course the $this keyword, which acts exactly the same as normal closures:

array_map(fn($x) => $x * $this->modifier, $numbers);

# Future possibilities

I already mentioned multi-line short closures, which is still a future possibility. Another idea floating around is allowing the short closure syntax in classes, for example for getters and setters:

class Post {
    private $title;
 
    fn getTitle() => $this->title;
}

All in all, short closures are a welcome feature, though there is still area for improvement. The biggest one probably being multi-line short closures.

Do you have any thoughts you'd like to share? Feel free to send a tweet or an email my way!