2009-06-11 17 views
6

Tengo un caso muy especial en el que necesito llamar a un método protegido desde fuera de una clase. Soy muy consciente de lo que hago de forma programada, pero no me opondría totalmente a hacerlo en este caso especial que tengo. En todos los demás casos, debo seguir denegando el acceso al método interno, por lo que me gustaría mantener el método protegido.Llamar a un método protegido desde fuera de una clase en PHP

¿Cuáles son algunas formas elegantes de acceder a un método protegido fuera de una clase? Hasta ahora, he encontrado this.

supongo que puede ser posible crear algún tipo de instancia de doble agente de la clase de destino que a escondidas proporcionar acceso a los componentes internos ...

+0

¿Cuál es la mejor manera de hacerlo? Cambie la función para ser pública. – Powerlord

Respuesta

0

sólo estoy lanzando esta ahí fuera, ya que no tengo programado en PHP en dos años. ¿Podría agregar una función a la clase que llama al método protegido de esa manera?

$obj->publicFunc = create_function('$arg', 'return $this->protectedFunc($arg);'); 

Editar: creo que Tom es correcta en el estudio de la documentación para create_function. Parece que el alcance de $ será "incorrecto" cuando intente llamarlo con este ejemplo.


Parece funciones anónimas tradicionales están soportados a partir de PHP 5.3.0, así (y mi primera solución, probablemente, no va a funcionar), así que probablemente iba a escribir que esta forma:

$obj->publicFunc = function($arg) { 
    return $this->protectedFunc($arg); 
}; 

Ya que creo que se ve un poco más limpio (y su IDE de elección lo resaltará mejor, por supuesto).


Uf, me trató de usar Reflection para llamar al método, pero PHP no le permitirá hacer eso. Parece que vas a tener que usar algún tipo de clase infantil como han sugerido los otros carteles. Si encuentras un método que funciona, los desarrolladores probablemente lo clasificarán como un error en el futuro y romperán tu código cuando actualices a la próxima versión.

Recomiendo extender la clase.

+0

Nono, es una buena oportunidad. Probablemente intentaré eso. Si funciona, te lo haré saber. –

+0

Creo que esto solo creará una cadena $ obj-> publicFunc que es el nombre de la nueva función. Cuando intentas llamarlo, el alcance es como para una función normal. –

+1

No estoy obteniendo esto funcionando: http://chadjohnson.ath.cx:8080/static/anonymous_function.phps. El error que recibo es "Llamar al método indefinido Chad :: publicFunction()". ¿Qué podría estar haciendo mal? –

1

Esto es un poco kludgy, pero podría ser una opción.

Añadir una clase hija por el bien de acceder a su función protegida

public class Child extends Parent { 
    public function protectedFunc() { 
     return parent::protectedFunc(); 
    } 
} 

A continuación, se crea una instancia de Child en lugar de Parent donde tiene que llamar a esa función.

+0

Hmm, sí, esta parece ser mi única opción en este punto. Tal vez debería llamar a esta clase Spy o_O. –

3

Creo que en este caso, refactorizar para que no requiera este tipo de cosas es probablemente la forma más elegante de hacerlo. Al decir que una opción es usar __call y dentro de ese análisis debug_backtrace para ver qué clase llamó al método. A continuación, consulte a un amigo whitelst

class ProtectedClass { 

    // Friend list 
    private $friends = array('secret' => array('FriendClass')); 

    protected function secret($arg1, $arg2) { 
     // ... 
    } 

    public function __call($method, $args) { 

     $trace = debug_backtrace(); 
     $class = $trace[1]['class']; 
     if(in_array($class, $this->friends[$method])) 
      return $this->$method($args[0], $args[1]); 

     throw new Exception(); 
    } 
} 

Creo que necesito una ducha.

+0

¿Por qué no usar reflejos? – Smar

0

Me gustaría pensar qué le pasa al diseño del programa si tengo que llamar a una función privada?

lo que solía ser el caso cuando

  • su clase es responsable de varias cosas (que es en realidad dos o thre calsses envueltos juntos) o
  • las reglas de encapsulación están rotos (funciones de utilidad, para ejemplo)

al encontrar cualquier manera de caminar por esta pregunta, habrá un lugar más cerca de la solución real.

+1

En general, este es un buen consejo. Pero a veces hay buenas razones para llamar a métodos fuera de su alcance definido. Por ejemplo, si no desea hacer que un método forme parte de su API, pero desea llamarlo en sus pruebas. O en las vistas de CodeIgniter, es posible que desee que su función hash de contraseña no se pueda llamar desde la web, pero sí desea llamarlas en sus pruebas. A diferencia de C++, PHP no tiene clases de "amigos" que tengan acceso privilegiado a las partes internas de la clase. – qris

+1

También si está utilizando una API de terceros que no expone el método, pero definitivamente necesita acceso a ese método. Definitivamente es un punto válido hecho por Csaba, pero en muy raras ocasiones, puede que tenga que romper las reglas. –

-3

Suponga que su declaración de método va así:

protected function getTheFoo() { 
    ... 
} 

protected function setTheFoo($val) { 
    ... 
} 

Uso:

$obj->__get('the_foo'); 
$obj->__set('the_foo', 'myBar'); 

Esto evita los métodos protegidos y va directamente directamente a las variables de instancia.

+0

No estoy obteniendo esto. – Mateng

4

En PHP puede hacer esto usando Reflejos. Para invocar métodos privados o protegidos, use el método setAccessible() http://php.net/reflectionmethod.setaccessible (simplemente configúrelo en TRUE)

+0

Debería indicar cómo hacer las cosas como respuesta, no para vincular alguna otra respuesta (en este caso, documentación). Sin embargo, le recomendamos que vincule a su fuente y a otros documentos importantes. – Smar

Cuestiones relacionadas