Переписывание анонимной функции в php 7.4

Существует следующая анонимная рекурсивная функция:

$f = function($n) use (&$f) {
    return ($n == 1) ? 1 : $n * $f($n - 1);
};

echo $f(5); // 120

Пытаюсь перепрошить на версию 7.4, но выходит ошибка, подскажите пожалуйста, что я упускаю?

$f = fn($n) => ($n == 1) ? 1 : $n * $f($n - 1);
echo $f(5);

Примечание: Неопределенная переменная: f

Неустранимая ошибка: необработанная ошибка: имя функции должно быть строкой


person морфиновые облака    schedule 15.11.2019    source источник
comment
Отвечает ли это на ваш вопрос? Как использовать стрелочные функции в PHP?   -  person Dharman    schedule 15.11.2019
comment
Вам нужен модификатор use(), чтобы вы могли ссылаться на внешнюю переменную $f.   -  person Barmar    schedule 15.11.2019
comment
Я не знаю, следует ли закрыть это как дубликат или ответить, поэтому я действительно ценю ваши отзывы. Пожалуйста, отметьте как принятое, если это помогло. Также есть этот пост: stackoverflow.com/a/56658110/1839439   -  person Dharman    schedule 15.11.2019
comment
Как указано в связанном вопросе, стрелочные функции будут захватывать внешние переменные по значению. Но исходная анонимная функция захватывается по ссылке. Я не думаю, что есть эквивалент со стрелочными функциями.   -  person Barmar    schedule 15.11.2019
comment
@Barmar, то есть без use() нельзя будет использовать в новом синтаксисе?   -  person морфиновые облака    schedule 15.11.2019


Ответы (3)


Как сказал Бармар, вы не можете использовать $f из внешней области, потому что когда происходит неявное связывание, $f все еще не определено.

Ничто не мешает вам передать его позже в качестве параметра.

$f = fn($f, $n) => $n == 1 ? 1 : $n * $f($f, $n - 1);
echo $f($f, 5); // 120

Принцип работы стрелочных функций заключается в том, что во время определения они будут использовать привязку по значению переменных внешней области видимости.

Как уже упоминалось, стрелочные функции используют привязку переменных по значению. Это примерно эквивалентно выполнению use($x) для каждой переменной $x, используемой внутри стрелочной функции. - https://wiki.php.net/rfc/arrow_functions_v2

Присвоение замыкания переменной $f происходит после определения замыкания, а переменная $f до него не определена.

Насколько мне известно, нет никакого механизма для привязки по ссылке при определении стрелочных функций.

person Dharman    schedule 15.11.2019
comment
О, немного неожиданно. Буду учитывать, большое спасибо! - person морфиновые облака; 15.11.2019

Я не думаю, что вы можете переписать функцию как функцию стрелки.

Стрелочная функция фиксирует значение любых внешних переменных по значению во время создания функции. Но $f не будет иметь значения до тех пор, пока функция не будет создана и не будет назначена переменная.

Исходная анонимная функция решает эту проблему, захватывая ссылку на переменную с use (&$f), а не use ($f). Таким образом, он сможет использовать обновленное значение переменной, полученное в результате присваивания.

person Barmar    schedule 15.11.2019
comment
Спасибо за объяснение. Жаль, можно ли считать, что это дефект функций стрелы? Надеюсь в скором времени что-нибудь с этим сделаю. - person морфиновые облака; 15.11.2019
comment
Стрелочные функции — это упрощение анонимных функций. - person Barmar; 15.11.2019

Я думаю, что только что нашел одно из законных (нет?) Использование $GLOBALS

$f = fn ($n) =>($n == 1) ? 1 : $n * $GLOBALS['f']($n - 1);
echo $f(5); // 120

Примечание: что, если $n < 1 ?

person Rain    schedule 09.01.2020
comment
О, Боже, это сумасшедшая идея. - person морфиновые облака; 10.01.2020
comment
в моей проблеме нет n < 1. Спасибо за ответ :) - person морфиновые облака; 10.01.2020
comment
@TheartofBeingalive Я знаю, но если кто-то передаст 0 или отрицательное число функции $f(0), функция будет вызывать себя НАВСЕГДА. - person Rain; 10.01.2020
comment
этого не должно происходить, потому что нет смысла использовать эту функцию, когда значение равно нулю. И если значение стремится к единице, функция выдаст ему такое же значение. - person морфиновые облака; 10.01.2020
comment
@TheartofBeingalive Это действительно имеет смысл. Потому что, насколько мне известно, это факториальная функция, а факториал 0! равен 1. - person Rain; 10.01.2020