2012-10-25 27 views
13

注意:由於寫了這個問題,我已經發現我對使用新的語言功能過於狂熱。更清潔的解決方案是使用戰略模式,而不是...仍然,我很好奇,如果有一個正確的方法去解決這個問題。如何獲取運行時確定可調用參數的數量?

TL; DR:您是否可以在PHP中使用泛型Callable而不訴諸手動查找各種可調用類型?

在PHP 5.4中,我們有一個新的提示:可調用。這看起來很有趣。我想我會利用這個通過如下:

<?php 
    public function setCredentialTreatment(callable $credentialTreatment) { 
     // Verify $credentialTreatment can be used (ie: accepts 2 params) 
     ... magic here ... 
    } 
?> 

到目前爲止,我的思路已經做了一系列的類型檢查的調用,並從其中推斷的反思*類使用:

<?php 
if(is_array($callable)) { 
    $reflector = new ReflectionMethod($callable[0], $callable[1]); 
} elseif(is_string($callable)) { 
    $reflector = new ReflectionFunction($callable); 
} elseif(is_a($callable, 'Closure') || is_callable($callable, '__invoke')) { 
    $objReflector = new ReflectionObject($callable); 
    $reflector = $objReflector->getMethod('__invoke'); 
} 

// Array of ReflectionParameters. Yay! 
$parameters = $reflector->getParameters(); 
// Inspect parameters. Throw invalidArgumentException if not valid. 
?> 

對我來說,這感覺過於複雜。我是否錯過某種實現我在此嘗試做的事情的捷徑?任何見解都會受到歡迎:)

+0

我遇到了類似的問題,並最終創建一個幫助函數來獲取任何可調用的Reflection對象。這個函數的代碼和你的代碼非常相似。 – Benjamin

+0

我不知道如果你繼續這樣做,但你有沒有考慮創建自己的CallableReflection,這有助於更輕鬆地打包差異? – hakre

+0

最後我還沒有進一步追求這個路徑,但是創建一個可重複使用的CallableReflection確實看起來像是朝着正確方向邁出的一步。不過,在某些時候,我期望PHP的Reflection模塊能夠在這些方面提供一些東西。 – kander

回答

2

我創建了一個與call_user_func()非常類似的短版本,並在PHP手冊中的所有不同類型上對回調/可調用函數進行了測試。這樣你幾乎可以在任何地方使用它。 call_user_func()不僅僅是對象,它對我來說也沒有意義,因爲它只處理回調函數。

測試和建議如何使用它下面包括在內,我希望這有助於:

function getNrOfParams($callable) 
{ 
    $CReflection = is_array($callable) ? 
    new ReflectionMethod($callable[0], $callable[1]) : 
    new ReflectionFunction($callable); 
    return $CReflection->getNumberOfParameters(); 
} 

測試及其結果的全部:

<?php 
class Smart 
{ 
    public function __invoke($name) 
    { 

    } 

    public function my_callable($one, $two, $three) 
    { 

    } 

    public static function myCallableMethod($one, $two) 
    { 

    } 

    public static function who() 
    { 
      echo "smart the parent class"; 
    } 
} 

class Smarter extends Smart 
{ 
    public static function who() 
    { 
     echo "smarter"; 
    } 
} 

function my_ca($one) 
{ 

} 

function getNrOfParams($callable) 
{ 
    $CReflection = is_array($callable) ? new ReflectionMethod($callable[0], $callable[1]) : new ReflectionFunction($callable); 
    return $CReflection->getNumberOfParameters(); 
} 
// Test 1 Callable Function 
echo "Test 1 - Callable function:" . getNrOfParams('my_ca'); 

// Test 2 Static method 
echo " Test 2 - Static class method:" . getNrOfParams(array('Smart', 'myCallableMethod')); 

// Test 3 Object method 
$smart = new Smart(); 
echo " Test 3 - Object method:" . getNrOfParams(array($smart, 'my_callable')); 

// Test 4 Static method call (As of PHP 5.2.3) 
//echo " Test 4 - Static class method call:" . getNrOfParams('Smart::myCallableMethod'); 
// Calling a static method this way does not work in ReflectionFunction. 
// However, Test 2 provides a solution. 

// Test 5 Relative static method (As of PHP 5.3.0) 
//echo " Test 5 - Relative static class method:" . getNrOfParams(array('Smarter', 'parent::who')); 
// Calling a relative static method doesn't work either. ReflectionMethod lacks support. 
// All other tests work. 

// Tesy 6 __invoke 
echo " Test 6 - __invoke:" . getNrOfParams(array($smart, '__invoke')); 

// Test 7 Closure 
$closure = function($one, $two, $three) 
{ 
    // Magic 
}; 
echo " Test 7 - Closure:" . getNrOfParams($closure); 
+0

太棒了!接受這個答案,因爲它涵蓋了我一直在尋找的一切......不錯的工作:) – kander

0

您可以傳遞數組參數並可以對數組值進行計數,以瞭解傳遞給回調函數的參數。

相關問題