2009-10-22 96 views
11

我有一個爲WSDL文件生成的SoapClient實例。除了方法調用之外的所有方法都需要用戶名和密碼通過id。是否可以在PHP中使用方法調用?

是否有任何方法來調用方法調用,以便我可以省略用戶名和密碼?

+0

你能給的你在想什麼的例子嗎? – Gumbo 2009-10-22 21:14:42

+0

查看VolkerK的回答。 – 2009-10-22 21:19:08

回答

16

從php 5.3開始,你可以在一個變量中存儲anonymous function。這個匿名函數可以用一些預定義的參數調用「原始」函數。

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

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

$bar('C'); 

編輯:您還可以使用閉包來parametrise匿名函數創建

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其他建議()和包裝類可能會更好,如果你想「增強」一個完整的類。

+0

這很整潔!我在PHP上有點生疏 - 我知道我可以列舉一個對象的方法,但我可以攔截它們嗎? – 2009-10-22 21:18:35

+0

你的意思是'magicTrampoline(array($ obj,'methodName'),$ myInterceptor)''這樣每當'$ obj-> methodName'被調用時,你在$ myInterceptor中的回調被調用(沒有$ obj明確地實現這樣的特性)? 'magicTrampoline()'會被允許返回一個新的對象嗎? – VolkerK 2009-10-22 21:25:15

+0

如果'magicTrampoline()'能夠添加到傳遞給$ obj-> methodName(...)的參數,那麼是的。 – 2009-10-22 21:51:55

2

雖然不是一個很好的解決方案,但您可以編寫一個基本的包裝類,它使用PHP magic methods(特別是__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); 
    } 
} 
+0

謝謝。那是'__call'方法IIRC嗎? – 2009-10-22 21:19:42

+0

call_user_func接受參數列表,而不是數組。你的解決方案只是將curried參數作爲數組發送給函數,而不是參數列表。但是,使用call_user_func_array()將工作:) – 2012-05-15 03:02:51

+1

@JohnKurlak修正了這個問題。 ;-) – Potherca 2015-08-01 21:49:09

3

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

我做了一些相關的研究這個今天。這是接近我可以得到:

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將不允許在未綁定的對象上執行的方法執行關閉)。但是,由於閉包是一個Closure類型的對象,它有一個內置方法__invoke(),所以上面的方法是可行的。

5

這裏是一個類實現自動鑽營和部分應用:

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

正如Ihor所提到的,非標準PHP庫很有趣。 我已經實現了相同的方法,它比伊霍爾的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); 
相關問題