如何编写可以在php中调用func(a)(b)(c)之类的函数?

时间:2018-10-03 12:34:10

标签: php

我需要实现像这样的功能“ calc”:

$sum = function($a, $b)  { return $a + $b; };
calc(5)(3)(2)($sum);    // 10
calc(1)(2)($sum);       // 3
calc(2)(3)('pow');      // 8

我可以这样写:

function calc(){;
    print_r(func_get_args());
    return __FUNCTION__;
}
calc(3)(5)(2)('sum');

并打印Array ( [0] => 3 ) Array ( [0] => 5 ) Array ( [0] => 2 ) Array ( [0] => sum )

所以,当我在函数中得到'sum'时,我应该有一个包含所有先前参数的数组。 但是我不知道,我如何在下一个函数调用中传递当前参数以在上一次迭代中操纵所有参数。还是有某种递归解决方案?

3 个答案:

答案 0 :(得分:3)

您所说的称为Currying。以下代码将需要PHP 7,因为它涉及到调用从另一个函数返回的函数,直到在该版本中实现PHP的Abstract Syntax Tree才可能。

首先,您需要一个新的sum()函数,该函数可以对任意数量的变量进行操作:

$sum = function(...$args)  { return array_sum($args); };

第二,重要部分。一个累加的函数将返回一个新的匿名函数,并随即累加参数。当您最终将其传递给某个可调用的对象(您的$sum函数或诸如pow之类的内置函数名称)时,它将执行它,解压缩它所构建的参数。

function calc($x)
{
    return function($y = null) use ($x)
    {
        if (is_callable($y)) {
            return $y(...$x);
        } else {
            $args = (array) $x;
            $args[] = $y;
            return calc($args);
        }
    };
}

echo calc(5)(3)(2)($sum); // 10
echo calc(1)(2)($sum); // 3
echo calc(2)(3)('pow'); // 8

请参见https://3v4l.org/r0emm

(请注意,内部函数将仅限于对其定义采用的参数数量进行操作-calc(2)(3)(4)('pow')会引发错误。)

这不是一种特别常用的模式(这可能就是为什么您很难找到它的原因),所以请阅读本书的每个人都仔细考虑使用它的位置。

记入this question中的curryAdd答案作为起点。

答案 1 :(得分:2)

编辑:我已纠正,您似乎不需要全局变量!绝对在这个问题上使用@iainn的答案。


因此,要实现此目的,如果您不打算在类中维护全局状态,则必须使用全局变量。您可以看到以下代码here的有效示例(请注意,它仅适用于PHP 7及更高版本)

<?php

$sum = function(...$args) {
    return array_sum($args);
};

function calc(...$args) {
    global $globalArguments;
    if (is_callable($args[0])) {
        $callback = $args[0];
        $arguments = array_map(function ($arg) {
            return $arg[0];
        }, $globalArguments);

        return $callback(...$arguments);
    }
    $globalArguments[] = $args;
    return __FUNCTION__;
}

echo calc(3)(2)($sum); // 5

我不知道您为什么要这样做,但我不建议在生产中使用它,如果可以避免的话,全局变量并不是真正应该使用的东西。

答案 2 :(得分:0)

function calc(int $value, Callable $function = null)
{
    return function ($v) use ($value, $function) {
        $f = function ($call) use ($value, $function) {
            return (is_callable($call) && is_callable($function)) ? $call($function($call), $value) : $value;
        };
        return is_callable($v) ? $f($v) : calc($v, $f);
    };
}