2010-11-12 7 views
19

Sto costruendo un'API in cui l'utente richiede un 'comando', che viene passato in una classe. Supponendo che il comando corrisponda a una funzione PUBLIC, verrà eseguito correttamente. Se il comando corrisponde a una funzione PROTETTA, deve generare un errore.Come verificare se una funzione è pubblica o protetta in PHP

L'idea è che le funzioni possono essere disabilitate modificandole da PUBLIC a PROTECTED, invece di rinominarle o rimuoverle.

Attualmente lo faccio, ma non importa se il comando è pubblico o protetto.

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

risposta

47

Basta usare 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

Stavo andando per questo, ma tu sei venuto prima di me :) –

+1

Impressionante, grazie :) –

7

È possibile utilizzare la funzione is_callable per determinare se il livello di protezione dovrebbe limitare voi: Esempio:

<?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

Non penso che is_callable funzioni quando sto chiamando da dentro la stessa classe (i metodi così protetti SONO chiamabile). –

+0

sei corretto - is_callable prende in considerazione lo scope corrente – rhollencamp

1

Anche se non si può distinguere se il il metodo è privato o protetto, puoi testare se pubblico anziché utilizzare un metodo esterno usando is_callable. Ho fatto un confronto con la risposta "meze".

Quindi:

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

Il metodo testIfCallable deve essere incluso in una classe comune o qualcosa di simile, che si ha nel proprio toolkit perché metodi globali non sono raccomandati.

Uso questo in combinazione con i metodi magici __get e __set per garantire un metodo pubblico "get/set".

Test:

//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>"; 

Uscite:

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

Considerazioni finali

Se hai bisogno di testare tra tutte le possibilità di visibilità, il tuo unico modo per andare è quello di utilizzare testIfCallable2 , quindi la risposta "meze". Altrimenti, la mia strada è circa due volte più veloce. Poiché la tua domanda era solo tra pubblico o no, potresti trarne beneficio. Dicendo che, se non lo usi spesso, la differenza non è significativa.

Problemi correlati