2010-09-14 15 views
6

Hola Necesito obtener solo los métodos declarados en una clase, y no los métodos heredados. Necesito esto para CakePHP. Estoy obteniendo todos los controladores, cargándolos y recuperando los métodos de esos controladores. Pero no solo están viniendo los métodos declarados, sino también los heredados.Obtener solo los métodos declarados de una clase en PHP

¿Hay algún método para obtener solo los métodos declarados?

+0

No conozco ningún método, excepto cosas complicadas de reflexión. ¿Para qué necesitas esto? –

+0

¿Puede decirme por qué está haciendo esto? ¿Es para documentación o para uso dentro de la aplicación? –

+0

Necesito agregar todos los métodos públicos en los controladores a mi tabla de permisos. Estoy usando CakePHP, y su componente de ACL no está funcionando con el modelo existente que tengo. – macha

Respuesta

9

Usted puede hacer esto (aunque un poco más que "simples") 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

¿por qué está utilizando 'ReflectionMethod :: IS_PUBLIC'? – chelmertz

+0

Para limitarlo solo a métodos públicos. Si desea todos los métodos, simplemente omita eso ... – ircmaxell

+0

Sin embargo, debe mencionarse, ya que hace que la respuesta sea incompleta a la pregunta. – chelmertz

1

Desde un punto de vista arquitectónico, creo que se debe evitar la reflexión si es posible, pero eche un vistazo a ReflectionClass->getMethods() si cree que sabe lo que está haciendo.

<?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()); 

?> 

Usted recibirá una lista de los métodos definidos por B y A, junto con la clase que se define última. Esta es la salida:

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

"Desde un punto de vista arquitectónico, creo que se debe evitar la reflexión si es posible" ¿por qué? – chelmertz

+2

Hm, supongo que es una preferencia personal. Para mí, la reflexión es similar a parchear ejecutables en memoria y * puede * ser inesperado (o exponer dicho comportamiento) a menos que esté bien documentado y puede hacer que su código sea más intrincado o introducir efectos colaterales. Sin embargo, puede resultar útil para escribir marcos y metaprogramar/ampliar las características de un idioma. – Archimedix

0

se encontró con un comentario: "ReflectionClass :: getMethods() ordena los métodos por clase (el más bajo en el árbol de herencia primero) y luego por el orden en que están definidos en la definición de clase "aquí - http://php.net/manual/en/reflectionclass.getmethods.php#115197

Lo verifiqué y parece ser cierto. Basado en el hecho, podemos agregar un poco de optimización a la solución de ircmaxell para evitar iterar sobre otros métodos heredados. También se ha agregado un poco de limpieza para evitar el 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; 
} 
Cuestiones relacionadas