В PHP 7.4 войдут стрелочные функции (сокращенная запись анонимных функций)

habr.png

Голосование по сокращенному синтаксису для функций завершено (51 «за», 8 «против»).

Было:

$result = array_filter($paths,  function ($v) use ($names) {
    return in_array($v, $names);
});

Стало:

$result = array_filter($paths,  fn($v) => in_array($v, $names));

Подробности под катом

Новый синтаксис такой:


Синтаксис

fn(список_параметров) => возвращаемое_выражение

В сигнатуре стрелочной функции, как и в обычной функции, можно указывать типы, дефолты и прочее

fn(array $x) => $x;
fn(): int => $x;
fn($x = 42) => $x;
fn(&$x) => $x;
fn&($x) => $x;
fn($x, ...$rest) => $rest;

Внимание! Появилось новое ключевое слово fn, а это означает обратную несовместимость!


Другие (отброшенные) идеи по синтаксису

Рассматривались варианты:

 // невозможно реализовать, путаница с элементами массивов в некоторых случаях
($x) => $x * $y

// так можно сделать, но слишком много фигурных скобок, особенно для вложенных функций
{ ($x) => $x + $y } 

// так сделано в языке Hack; но слишком сложно для текущего парсера 
($x) ==> $x * $y

// нереализуемо, путаница с получением свойств объекта 
($x) -> $x * $y

// сейчас парсер это понимает как $x--  > $x*$y  
$x --> $x * $y 

// так сделано в Rust, но читабельность спорна
|$x| => $x * $y 

и некоторые другие


Замыкание переменных

Важно! В отличие от предыдущих версий php, где надо было явно задавать замыкаемые переменные оператором use, стрелочная функция неявно замыкает на себе весь родительский скоуп.

Вот эквивалентные записи:

$y = 1;

$fn1 = fn($x) => $x + $y;

$fn2 = function ($x) use ($y) {
    return $x + $y;
};

Переменная $this замыкается точно также, как и любая другая переменная. Если это нежелательное поведение, можно его запретить ключевым словом static.

class Test {
    public function method() {
        $fn = fn() => var_dump($this);
        $fn(); // object(Test)#1 { ... }

        $fn = static fn() => var_dump($this);
        $fn(); // Error: Using $this when not in object context
    }
}

Замыкание переменных в стрелочных функциях происходит по значению (в отличие от языка Go, например). Т.е. изменение переменных внутри функции не приведет к изменению переменной в родительском скоупе.


Выводы

Код стал значительно компактнее, и хотя не такой компактный, как в javascript и некоторых других языках, но всё же писать будет значительно приятнее:

$result = Collection::from([1, 2])
    ->map(fn($v) => $v * 2)
    ->reduce(fn($tmp, $v) => $tmp + $v, 0);

echo $result; //6

В отличие от некоторых других языков стрелочные функции в php не поддерживают несколько statements, разделенных через символ ;, потому что это (по мнению авторов RFC) противоречит идее сокращенного синтаксиса. Возможно это будет пересмотрено в будущем.

Мы обязательно детально обсудим стрелочные функции в php в подкасте «Цинковый прод», так что не забудьте подписаться.

Ссылка на RFC: https://wiki.php.net/rfc/arrow_function

© Habrahabr.ru