2010-09-14 14 views
6

Ciao Ho bisogno di ottenere solo i metodi dichiarati in una classe e non i metodi ereditati. Ho bisogno di questo per cakePHP. Sto ricevendo tutti i controller, caricandoli e recuperando i metodi da quei controller. Ma non solo vengono i metodi dichiarati, ma anche quelli ereditati.Ottieni solo metodi dichiarati di una classe in PHP

Esiste un metodo per ottenere solo metodi dichiarati.

+0

Non conosco alcun metodo eccetto le complicate cose di riflessione. Per cosa ti serve questo? –

+0

Puoi farmi sapere perché stai facendo questo? È per la documentazione o per l'uso all'interno dell'applicazione? –

+0

Ho bisogno di aggiungere tutti i metodi pubblici nei controller alla mia tabella delle autorizzazioni. Sto usando cakePHP e il loro componente ACL non funziona con il modello esistente che possiedo. – macha

risposta

9

Si può fare questo (anche se un po 'più di "semplice"), con ReflectionClass

function getDeclaredMethods($className) { 
    $reflector = new ReflectionClass($className); 
    $methodNames = array(); 
    $lowerClassName = strtolower($className); 
    foreach ($reflector->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { 
     if (strtolower($method->class) == $lowerClassName) { 
      $methodNames[] = $method->name; 
     } 
    } 
    return $methodNames; 
} 
+0

perché stai usando 'ReflectionMethod :: IS_PUBLIC'? – chelmertz

+0

Per limitarlo a metodi solo pubblici. Se vuoi tutti i metodi, ometti semplicemente ... – ircmaxell

+0

Dovrebbe essere menzionato, poiché rende la risposta incompleta alla domanda. – chelmertz

1

Da un punto di vista architettonico, penso che la riflessione dovrebbe essere evitata se possibile, ma date un'occhiata allo ReflectionClass->getMethods() se pensate di sapere cosa state facendo.

<?php 

class A { 
    public function x() { } 
    public function y() { } 
} 

class B extends A { 
    public function a() { } 
    public function b() { } 
    public function x() { } // <-- defined here 
} 

$r = new ReflectionClass('B'); 
print_r($r->getMethods()); 

?> 

Si otterrà un elenco dei metodi definiti da B e A, insieme con la classe che lo scorso ha definito. Questa è l'uscita:

Array 
(
    [0] => ReflectionMethod Object 
     (
      [name] => a 
      [class] => B 
     ) 

    [1] => ReflectionMethod Object 
     (
      [name] => b 
      [class] => B 
     ) 

    [2] => ReflectionMethod Object 
     (
      [name] => x 
      [class] => B 
     ) 

    [3] => ReflectionMethod Object 
     (
      [name] => y 
      [class] => A 
     ) 

) 
+0

"Da un punto di vista architettonico, penso che la riflessione dovrebbe essere evitata se possibile" perché è così? – chelmertz

+2

Hm, immagino sia una preferenza personale. Per me, la riflessione è simile al patching degli eseguibili in memoria e * può * essere inaspettato (o esporre tale comportamento) se non ben documentato e può rendere il vostro codice più complicato o introdurre effetti collaterali. Tuttavia, potrebbe rivelarsi utile per scrivere framework e meta-programmazione/estendere le funzionalità di una lingua. – Archimedix

0

sono imbattuto in un commento: "ReflectionClass :: GetMethods() ordina i metodi per classe (più in basso nell'albero di ereditarietà) poi nell'ordine in cui sono definiti nella definizione di classe "qui - http://php.net/manual/en/reflectionclass.getmethods.php#115197

Ho verificato questo e sembra essere vero. Sulla base del fatto, possiamo aggiungere una piccola ottimizzazione alla soluzione di ircmaxell per evitare di iterare su altri metodi ereditati. Aggiunti anche alcuni clean up per evitare constructor \ destructor:

public function getMethods($className) 
{ 
    $methodNames = []; 
    $reflectionClass = new ReflectionClass(className); 
    $publicMethods = $reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC); 
    $lowerClassName = strtolower($className); 
    foreach ($publicMethods as $method) { 
     if (strtolower($method->class) == $lowerClassName) { 
      // You can skip this check if you need constructor\destructor 
      if (!($method->isConstructor() || 
       $method->isDestructor())) { 
       $methodNames[] = $method->getName(); 
      } 
     } else { 
      // exit loop if class mismatch 
      break; 
     } 
    } 
    return $methodNames; 
} 
Problemi correlati