Is it possible to curry method calls in PHP?

Here is a class implements automatic currying and partial application:

class lambda
{
    private $f;
    private $args;
    private $count;
    public function __construct($f, $args = [])
    {
        if ($f instanceof lambda) {
            $this->f = $f->f;
            $this->count = $f->count;
            $this->args = array_merge($f->args, $args);
        }
        else {
            $this->f = $f;
            $this->count = count((new ReflectionFunction($f))->getParameters());
            $this->args = $args;
        }
    }

    public function __invoke()
    {
        if (count($this->args) + func_num_args() < $this->count) {
            return new lambda($this, func_get_args());
        }
        else {
            $args = array_merge($this->args, func_get_args());
            $r = call_user_func_array($this->f, array_splice($args, 0, $this->count));
            return is_callable($r) ? call_user_func(new lambda($r, $args)) : $r;
        }
    }
}
function lambda($f)
{
    return new lambda($f);
}

Example:

$add = lambda(function($a, $b) { 
    return $a + $b; 
});
$add1 = $add(1);
echo $add1(2); // 3

Even you can do this:

$int1 = lambda(function($f, $x) {
    return $f($x);
});

$successor = lambda(function($p, $f, $x) {
    return $f($p($f, $x));
}); 

$add = lambda(function($p, $q, $f, $x) {
    return $p($f, $q($f, $x));
}); 

$mul = lambda(function($p, $q, $x) {
    return $p($q($x));
}); 

$exp = lambda(function($m, $n) {
    return $n($m);
});

$int2 = $successor($int1);
$int3 = $add($int1, $int2);
$int6 = $mul($int3, $int2);
$int8 = $exp($int2, $int3);

As of php 5.3 you can store an anonymous function in a variable. This anonymous function can call the "original" function with some predefined parameters.

function foo($x, $y, $z) {
  echo "$x - $y - $z";
}

$bar = function($z) {
  foo('A', 'B', $z);
};

$bar('C');

edit: You can also use a closure to parametrise the creation of the anonymous function

function foo($x, $y, $z) {
  echo "$x - $y - $z";
}

function fnFoo($x, $y) {
  return function($z) use($x,$y) {
    foo($x, $y, $z);
  };
}

$bar = fnFoo('A', 'B');
$bar('C');

edit2: This also works with objects

class Foo {
  public function bar($x, $y, $z) {
    echo "$x - $y - $z";
  }
}

function fnFoobar($obj, $x, $z) {
  return function ($y) use ($obj,$x,$z) {
    $obj->bar($x, $y, $z);
  };
}

$foo = new Foo;
$bar = fnFoobar($foo, 'A', 'C');
$bar('B');

But the other suggestions using __call() and a wrapper class may be better if you want to "enhance" a complete class.

Tags:

Php

Currying

Soap