2010-11-12 59 views
19

我正在構建一個API,用戶請求一個傳遞到類中的'command'。假設該命令匹配PUBLIC函數,它將成功執行。 如果該命令與PROTECTED函數匹配,則需要引發錯誤。如何檢查一個函數是公共的還是以PHP保護的

想法是,可以通過將功能從PUBLIC更改爲PROTECTED來禁用功能,而不是重命名或刪除它們。

我目前這樣做,但命令是公開還是保護無關緊要。

<?php 
/** 
* Look for Command method 
*/ 
$sMethod = "{$sCommand}Command"; 
if (method_exists($this, $sMethod)) 
{ 
    /** 
    * Run the command 
    */ 
    return $this->$sMethod($aParameters); 
} 

回答

47

只需使用ReflectionMethod

/** 
* Look for Command method 
*/ 
if (method_exists($this, $sMethod)) 
{ 
    $reflection = new ReflectionMethod($this, $sMethod); 
    if (!$reflection->isPublic()) { 
     throw new RuntimeException("The called method is not public."); 
    } 
    /** 
    * Run the command 
    */ 
    return $this->$sMethod($aParameters); 
} 
+0

我是爲這一個,但你來到我面前:) – 2010-11-12 01:45:40

+1

真棒,謝謝:) – 2010-11-12 02:01:53

7

可以使用is_callable功能,以確定保護級別應限制你:例:

<?php 
class FooBar { 
    protected function Foo() { return; } 
    public function Bar() { return; } 
} 

$foo = new FooBar(); 

var_dump(is_callable(array($foo, 'Foo'))); 
var_dump(is_callable(array($foo, 'Bar'))); 
+4

我不認爲is_callable工程,當我從同一類內部調用(所以被保護的方法可調用)。 – 2010-11-12 02:03:00

+0

你是正確的 - is_callable將當前範圍考慮在內 – rhollencamp 2010-11-13 01:32:12

1

雖然你不能,如果區分方法是私人的或受保護的,您可以測試公開與不使用is_callable的外部方法。我與「meze」的答案進行了比較。

所以:

function testIfCallable($object, $method) { 
    return is_callable(array($object, $method)); 
} 

function testIfCallable2($object, $method) { 
    if (method_exists($object, $method)) 
    { 
     $reflection = new ReflectionMethod($object, $method); 
     return $reflection->isPublic(); 
    } 

    return false; 
} 

class Test { 

    private function privateMethod() { 

    } 

    protected function protectedMethod() { 

    } 

    public function publicMethod() { 

    } 

    public function testAccessibility() { 
     if (testIfCallable($this, 'privateMethod')) echo "YYY<br>"; else echo 'NNN<br>'; 
     if (testIfCallable($this, 'protectedMethod')) echo "YYY<br>"; else echo 'NNN<br>'; 
     if (testIfCallable($this, 'publicMethod')) echo "YYY<br>"; else echo 'NNN<br>'; 
    } 

    public function testAccessibility2() { 
     if (testIfCallable2($this, 'privateMethod')) echo "YYY<br>"; else echo 'NNN<br>'; 
     if (testIfCallable2($this, 'protectedMethod')) echo "YYY<br>"; else echo 'NNN<br>'; 
     if (testIfCallable2($this, 'publicMethod')) echo "YYY<br>"; else echo 'NNN<br>'; 
    }  

    public function testSpeedAccessibility() { 
     return $results = [ 
       testIfCallable($this, 'privateMethod'), 
       testIfCallable($this, 'protectedMethod'), 
       testIfCallable($this, 'publicMethod') 
     ]; 
    } 

    public function testSpeedAccesibility2() { 
     return $results = [ 
       testIfCallable2($this, 'privateMethod'), 
       testIfCallable2($this, 'protectedMethod'), 
       testIfCallable2($this, 'publicMethod') 
     ]; 
    } 
} 

方法testIfCallable應包括在一個共同的類或你有你自己的工具包,因爲不推薦使用全局方法類似。

我使用這個結合魔術方法__get__set來確保存在公共的「get/set」方法。

測試:

//Test functionality 
$t = new Test(); 
$t->testAccessibility(); 
$t->testAccessibility2(); 

//Test speed 
$start = microtime(true); 
for($i = 0; $i < 10000; $i++) { 
    $t->testSpeedAccessibility(); 
} 
echo "Is Callable way: " . (microtime(true) - $start) . "ms<br>"; 

$start = microtime(true); 
for($i = 0; $i < 10000; $i++) { 
    $t->testSpeedAccesibility2(); 
} 
echo "Reflection way: " . (microtime(true) - $start) . "ms<br>"; 

輸出:

NNN 
NNN 
YYY 
NNN 
NNN 
YYY 
Is Callable way: 0.23506498336792ms 
Reflection way: 0.45829010009766ms 

最後的想法

如果你需要所有的知名度可能性之間進行測試,你只能去的方法是使用testIfCallable2 ,所以「meze」的答案。否則,我的方式快兩倍左右。由於你的問題只是在公衆之間,你可以從中受益。說這個,如果你不經常使用它,差異就不明顯了。

相關問題