Каррирование в PHP

На этот раз я пытаюсь реализовать каррирование в 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

Отвечает ли это на ваш вопрос? Можно ли каррировать вызовы методов в PHP? . Я предлагаю вам взглянуть на принятый ответ (и те, у кого есть голоса), чтобы увидеть, соответствует ли какой-либо из них вашим требованиям.

Ken Lee 10.05.2023 10:10

@KenLee Хорошо, я посмотрел на обман, но принятый ответ кажется далеким от каррирования. Он просто вернул функцию и вызвал ее, передав аргументы, что не является основной целью каррирования. Этот ответ выглядит близко, но я предполагаю, что локальные переменные в лексической области видимости анонимной функции уничтожаются после выхода из вызова функции, в отличие от Javascript, поскольку переменная остается в живых до тех пор, пока не перестанут вызываться внутренняя анонимная функция и мусор коллектор делает свое дело.

Vivek 10.05.2023 10:19
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
1
2
57
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Хорошо, это была довольно интересная проблема для меня. Каррирование имеет хороший синтаксический сахар наряду с несколькими другими преимуществами (например, при ведении журнала мы можем кэшировать дату и время для нескольких вызовов методов оператора журнала 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";

Онлайн демо

Другие вопросы по теме