Comparing arrow functions in JavaScript and PHP

Comparing arrow functions in JavaScript and PHP

14 Nov 2021 php

When arrow functions landed in ECMA 6, they allowed developers to be much more fluid with use of functions. Suddenly, you could have short-syntax anonymous functions that also inherited the parent scope.

this.foo = 'bar'; let func = () => console.log(this.foo); func(); //"bar"

PHP gained its own version of arrow functions in version 7.4, in 2019. The two key points are the same - i.e. that they allow for short-syntax function expression and inherit the parent scope - but they have some differences, too.

Let's take a look at the syntax, firstly. In PHP, arrow functions look broadly like this:

$double = fn($num) => $num * 2;

Notice the fn? That always has to be there. Not sure why the PHP designers thought that was necessary, but there you go.

You can still add type/return bindings if you like.

$double = fn(int $num):int => $num * 2;

But this is where the differences start. You can't, for example, omit the parentheses around arguments like you can in JavaScript if you pass only a single argument. In JavaScript, the following are equivalent:

let func1 = singleArg => 'return val'; let func2 = (singleArg) => 'return val';

In PHP, the parentheses are a must. This is presumably to separate the argument from the non-negotiable fn part.

fn $singleArg => true; //syntax error

Furthermore, arrow functions in PHP can perform only single expressions, unlike in JavaScript where you can group multiple expressions together as a block.

fn($arg) => { doSomething(); andSomethingElse(); } //syntax error

Another interesting difference is that, unlike with JavaScript, arrow functions in PHP cannot modify outside variables.This is because they use what's called "by-value" bindings - in other words, the arrow function has access only to copies of the values of outer variables, rather than references to them.

So this, for example, has no effect:

$a = 14; $incr = fn($a) => $a++; $incr($a); echo $a; //still 14

We can get round this in the usual fashion, by forcing the value to arrive by reference via &.

$a = 14; $incr = fn(&$a) => $a++; //<-- note & $incr($a); echo $a; //15!

I hope you found this comparison helpful!

Did I help you? Feel free to be amazing and buy me a coffee on Ko-fi!