WSDLファイル用に生成されたSoapClientインスタンスがあります。メソッド呼び出しの1つを除くすべてで、ユーザー名とパスワードにIDを渡す必要があります。
ユーザー名とパスワードを省略できるようにメソッド呼び出しをカリー化する方法はありますか?
WSDLファイル用に生成されたSoapClientインスタンスがあります。メソッド呼び出しの1つを除くすべてで、ユーザー名とパスワードにIDを渡す必要があります。
ユーザー名とパスワードを省略できるようにメソッド呼び出しをカリー化する方法はありますか?
php 5.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()とラッパークラスを使用した他の提案の方が適している場合があります。
自動カリー化と部分適用を実装するクラスを次に示します。
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);
}
例:
$add = lambda(function($a, $b) {
return $a + $b;
});
$add1 = $add(1);
echo $add1(2); // 3
あなたでもこれを行うことができます:
$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);
今日、これに関連するいくつかの調査を行いました。これは私が得ることができる限り近いです:
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 がバインドされていないオブジェクトに対してメソッドを実行できないのと同じように)。ただし、クロージャーは組み込みメソッド __invoke() を持つタイプ Closure のオブジェクトであるため、上記は機能します。
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');
あまり良い解決策ではありませんが、PHPのマジック メソッド(具体的には __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 ライブラリの部分適用関数とカレー関数を使用できます。