На этот раз я пытаюсь реализовать каррирование в PHP (точно так же, как мы делаем это в Javascript). Ниже мой код, который не работает:
<?php
function test(callable $fn){
$reflection = new ReflectionFunction($fn);
$args = count($reflection->getParameters());
$curried = function(...$currArgs) use($args, $fn){
if (count($currArgs) == $args){
return $fn(...$currArgs);
}else{
return function(...$currArgs2) use($args, $fn, $currArgs){
return $curried(array_merge($currArgs, $currArgs2));
};
}
};
return $curried;
}
$c = test(fn($x, $y, $z) => $x + $y + $z);
echo $c(10)(20,30);
Проблема:
Это дает мне неопределенную переменную $curried, как вы можете видеть здесь.
Вопрос:
Как мы можем рекурсивно вызывать одну и ту же каррированную функцию, поскольку я не вижу способа добиться этого здесь?
Ожидаемый результат:
Ожидаемый результат должен быть 60 как в обратном вызове fn($x, $y, $z) => $x + $y + $z
@KenLee Хорошо, я посмотрел на обман, но принятый ответ кажется далеким от каррирования. Он просто вернул функцию и вызвал ее, передав аргументы, что не является основной целью каррирования. Этот ответ выглядит близко, но я предполагаю, что локальные переменные в лексической области видимости анонимной функции уничтожаются после выхода из вызова функции, в отличие от Javascript, поскольку переменная остается в живых до тех пор, пока не перестанут вызываться внутренняя анонимная функция и мусор коллектор делает свое дело.






Хорошо, это была довольно интересная проблема для меня. Каррирование имеет хороший синтаксический сахар наряду с несколькими другими преимуществами (например, при ведении журнала мы можем кэшировать дату и время для нескольких вызовов методов оператора журнала DEBUG/INFO без необходимости передавать параметр datetime для каждого оператора журнала).
Во-первых, $curried недоступен при рекурсивном вызове внутри нового анонимного обратного вызова. Чтобы это работало, нам нужно передать эту переменную в use параметрах по ссылке.
Во-вторых, похоже, у нас нет никакого преимущества в вычислении количества параметров вне обратного вызова. Итак, мы помещаем это внутрь обратного вызова.
В-третьих, в $curried(array_merge($currArgs, $currArgs2)) я не передавал их как аргументы переменной длины, что вызывало проблему при вычислении количества параметров. Итак, исправление $curried(...array_merge($currArgs, $currArgs2)).
Окончательный рабочий код:
<?php
function test(callable $fn){
$curried = function(...$currArgs) use(&$fn, &$curried){
$reflection = new ReflectionFunction($fn);
$args = count($reflection->getParameters());
if (count($currArgs) == $args){
return $fn(...$currArgs);
}else{
return function(...$currArgs2) use( $fn, $currArgs, &$curried){
return $curried(...array_merge($currArgs, $currArgs2));
};
}
};
return $curried;
}
$c = test(fn($x, $y, $z) => $x + $y + $z);
echo $c(10)(20,30),"\n";
echo $c(10,20)(30),"\n";
echo $c(10,20,30),"\n";
Отвечает ли это на ваш вопрос? Можно ли каррировать вызовы методов в PHP? . Я предлагаю вам взглянуть на принятый ответ (и те, у кого есть голоса), чтобы увидеть, соответствует ли какой-либо из них вашим требованиям.