PHP 7.4 : Arrow Functions
18, December 2019

Full Disclosure: I don't like Arrow Functions (yet). But there are many things I don't like in PHP but still use everday. So Let there be another one.


What the heck is Arrow Functions?

You have used Anonymous functions, also known as closures, right? Arrow Functions are just synthetic sugar for it.

Example: To filter array based on custom logic, currently we pass a anonymous function to it like this

<?php

$array_with_string_and_int = ['a', 6, 'h', 30, 'z', 'm', 70];

$array_with_only_int = array_filter($array_with_string_and_int,
                                    function($value){
                                        return is_int($value);
                                     });

print_r($array_with_only_int);

// Array ( [1] => 6 [3] => 30 [6] => 70 )

With Arrow Function, we can write same thing in shorter manner. We don''t even need to write return keyword.

<?php

$array_with_string_and_int = ['a', 6, 'h', 30, 'z', 'm', 70];

$array_with_only_int = array_filter($array_with_string_and_int, fn($value) => is_int($value));

print_r($array_with_only_int);
// Array ( [1] => 6 [3] => 30 [6] => 70 )


There are another feature of arrow functions other than being shorter:

Inside arrow functions, you can access variables from its outer scope. So, you don't have to manually import them by use()

$multiplier = 10;

$array = [1, 2, 3, 4, 5, 6, 7, 8, 9];

$new_array = array_map(fn($number) => $number * $multiplier, $array);

print_r($new_array);
// Array ( [0] => 10 [1] => 20 [2] => 30 [3] => 40 [4] => 50 [5] => 60 [6] => 70 [7] => 80 [8] => 90 )

Here we can access $multiplier easily inside arrow functions. When we use variables from outer scope in arrow function, PHP automatically imports them into current scope.


Limitations

  • Arrow functions can't contain multiple expression. Only one expression can be used in function body and output of that expression is automatically returned as return value.
$array = [1, 2, 3, 4, 5, 6, 7, 8, 9];
 
$new_array = array_map(fn($time) => $now = time(); $time > $now ? 0 : 1, $array);
// This won't work. we have to keep our logic in one expression

$new_array = array_map(fn($time) => $time > time() ? 0 : 1, $array);
// This will work fine, because now we are using only one expression
// Note: You can't use multi-line either.
  • Arrow functions don't support statement. So you can't use any php statement (if-else, while, switch, exception throwing..etc) inside arrow functions.
$closure = fn() => echo time(); // Won't work, echo is a statement
  • Accessing variables by reference from outer scope is not possible. Arrow functions access variables from outer scope by pass-by-value.
$name = 'Alice';
 
$closure = fn() => $name = 'Bob';
 
$closure();
 
var_dump($name);
string(5) "Alice"

// $name didn't change to Bob because PHP imported outer variable by value
// So even if we change outer variable inside arrow function, it won't change

But, we can pass parameters to arrow functions by reference if we want to change it inside function

$name = 'Alice';
 
$closure = fn(&$name) => $name = 'Bob'; // & means variable $name will be passed by reference
 
$closure($name);
 
var_dump($name);
string(3) "Bob" // Now it has changed