可以在PHP中进行curry方法调用吗?

可以在PHP中进行curry方法调用吗?,php,soap,currying,Php,Soap,Currying,我为WSDL文件生成了一个实例。除一个方法调用外,所有方法调用都需要传递用户名和密码 是否有任何方法可以对方法调用进行循环,以便省略用户名和密码?从PHP5.3开始,您可以在变量中存储。此匿名函数可以使用一些预定义参数调用“原始”函数 function foo($x, $y, $z) { echo "$x - $y - $z"; } $bar = function($z) { foo('A', 'B', $z); }; $bar('C'); 编辑:还可以使用闭包来参数化匿名函数的创

我为WSDL文件生成了一个实例。除一个方法调用外,所有方法调用都需要传递用户名和密码


是否有任何方法可以对方法调用进行循环,以便省略用户名和密码?

从PHP5.3开始,您可以在变量中存储。此匿名函数可以使用一些预定义参数调用“原始”函数

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

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

$bar('C');
编辑:还可以使用闭包来参数化匿名函数的创建

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:这也适用于对象

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');

但是,如果您想“增强”一个完整的类,那么使用_call()和包装类的其他建议可能会更好。

虽然不是一个很好的解决方案,但您可以编写一个基本的包装类,使用PHPs(特别是_call)调用实际函数,但将用户名和密码附加到参数列表中

基本示例:

class SC
{
    private $user;
    private $pass;

    public function __construct($user, $pass)
    {
        $this->user = $user;
        $this->pass = $pass;
    }

    public function __call($name, $arguments) 
    {
        $arguments = array_merge(array($this->user, $this->pass), $arguments);  
        call_user_func_array($name, $arguments);
    }
}

PHP本身没有咖喱,但您可以通过几种方式来做类似的事情。在您的特定情况下,类似的方法可能会起作用:

class MySoapClient extends SoapClient {
  ...
  public function __call($meth,$args) {
    if (substr($method,0,5) == 'curry') {
      array_unshift($args,PASSWORD);
      array_unshift($args,USERNAME);
      return call_user_func_array(array($this,substr($meth,5)),$args);
    } else {
      return parent::__call($meth,$args);
    }
  }
}
$soapClient = new MySoapClient();
...
// now the following two are equivalent
$soapClient->currysomeMethod($additionalArg);
$soapClient->someMethod(USERNAME,PASSWORD,$additionalArg);
尽管在PHP>=5.3中有一个更通用的咖喱解决方案:

$curriedMethod = function ($additionalArg) use ($soapClient) { return $soapClient->method(USERNAME,PASSWORD,$additionalArg); }

$result = $curriedMethod('some argument');

我今天做了一些相关的研究。这是我能得到的最接近的结果:

function curryAdd($x)
{
  return function($y = null) use ($x)
  {
    if (is_null($y)) return $x;
    else return curryAdd($x + $y);
  };
}

// echo curryAdd(1)(2)(3)(4);
echo curryAdd(1)
  ->__invoke(2)
  ->__invoke(3)
  ->__invoke(4)
  ->__invoke();

主要问题是PHP不允许直接对返回值执行闭包(与PHP不允许对未绑定对象执行方法的方式大致相同)。但是,由于闭包是闭包类型的对象,它有一个内置的方法uu invoke(),上述方法将起作用。

这里有一个类实现了自动转换和部分应用程序:

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);
}
function sum3($x, $y, $z) {
    return $x + $y + $z;
}

function partial_sum3($x) {
    return function($y, $z) use($x) {
        return sum3($x, $y, $z);
    };
}

//create the partial
$f1 = partial_sum3(6);
//execute the partial with the two remaining arguments
$result = $f1(6, 6);

var_dump($result);

//OUTPUT:
int 18
即使您也可以这样做:

$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);

您可以从中使用和函数。

正如Ihor所提到的,非标准PHP库非常有趣。 我已经实现了相同的方法,它与Ihor的
curried()
函数有些不同

function curryfy($f, $args = []) {
    $reflexion = new ReflectionFunction($f);
    $nbParams = $reflexion->getNumberOfParameters();

    return function (...$arguments) use ($f, $reflexion, $nbParams, $args) {
        if (count($args) + count($arguments) >= $nbParams) {
            return $reflexion->invokeArgs(array_merge($args, $arguments));
        }

        return curryfy($f, array_merge($args, $arguments));
    };
}
用法:

function display4 ($a, $b, $c, $d) {
    echo "$a, $b, $c, $d\n";
};
$curry4 = curryfy('display4');
display4(1, 2, 3, 4);
$curry4(1)(2)(3)(4);
这个答案没有表现出谄媚。这个答案显示了部分应用。这里可以看到一个很好的教程,它解释了这些概念之间的区别:

这就是咖喱:

function sum3($x, $y, $z) {
    return $x + $y + $z;
}

// The curried function    
function curried_sum3($x) {
    return function ($y) use ($x) {
        return function ($z) use ($x, $y) {
            return sum3($x, $y, $z);
        };
    };
}
在PHP7中调用curried函数

$result = curried_sum3(1)(2)(3); 
var_dump($result); // int 6
在PHP5中调用curried函数

$f1 = curried_sum3(6);
$f2 = $f1(6);
$result = $f2(6);
var_dump($result);

//OUTPUT:
int 18
这是部分应用程序:

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);
}
function sum3($x, $y, $z) {
    return $x + $y + $z;
}

function partial_sum3($x) {
    return function($y, $z) use($x) {
        return sum3($x, $y, $z);
    };
}

//create the partial
$f1 = partial_sum3(6);
//execute the partial with the two remaining arguments
$result = $f1(6, 6);

var_dump($result);

//OUTPUT:
int 18

你能举例说明你在想什么吗?太好了!我对PHP有点生疏-我知道我可以列举一个对象的方法,但是我可以拦截它们吗?你的意思是像
magicTrampoline(array($obj,'methodName'),$myInterceptor)
这样,每当调用
$obj->methodName
时,$myInterceptor中的回调都会被调用(没有$obj显式实现这样的功能)?是否允许
magicTrampoline()
返回新对象?如果
magicTrampoline()
能够添加到传递给$obj->methodName(…)的参数中,是的。这是处理问题的一个非常好的方法。但是,这不是咖喱。如果您想了解如何在PHP中使用Curry,请参阅以下答案:谢谢。方法IIRC?call\u user\u func接受参数列表,而不是数组。您的解决方案只是将当前参数作为数组发送给函数,而不是参数列表。但是,使用call_user_func_array()将起作用:)@JohnKurlak修复了这一问题。;-)从PHP7开始,短咖喱是可能的。因此,
$result=curried_sum3(1)(2)(3)有效。@Alfred我在PHP7.0.1中测试了它。你是100%正确的。我将改变我的回答。无论如何,我发现在新功能页面中没有提到这个功能是不合适的。你能解释为什么php7的制造商没有提到这一点吗?我也没有在新功能列表中找到它。我通过在不同版本上测试发现了这一点。我认为这是在PHP7中使用闭包的一个特性。@Alfred我在评论部分找到了这一点。不过,当我想了解php的新特性时,这并不是我首先要找的地方。但有趣的是,在PHP7中,函数式编程是如何变得更容易访问的。