2009-10-01 12 views
14

El proyecto en el que estoy trabajando contiene algo así como un contenedor para call_user_func (_array) que realiza algunas comprobaciones antes de la ejecución. Una de esas comprobaciones es method_exists (en caso de que el primer argumento proporcionado sea una instancia de una clase y el segundo es un nombre de método) La otra is_callable. La función arrojará una excepción si falla una de esas comprobaciones.PHP __call vs method_exists

Mi código contiene una matriz con nombres de función (setFoo, setBar, etc.) y la función mágica php para sobrecargar (__call) que maneja la configuración, sustitución y eliminación de ciertas variables (mejores ciertos elementos de la matriz).

El problema: method_exists devolverá falso si la función no está definida.

¿Tengo alguna posibilidad de obtener un verdadero si la función __call hace un correcto manejo de la solicitud?

+0

Gran pregunta, voy a jugar un poco con esto. –

+0

Lo que se necesita es otro "método mágico" __canCall o algo así ... –

+1

is_callable() funciona con instancias de clases. No veo por qué estás usando method_exists() en absoluto. is_callable() hace todo lo que method_exists() hace más funciona con __call(). – dave1010

Respuesta

4

method_exists trata de dos cosas:

  • Busca el nombre del método en la tabla de funciones de la clase. Esos son los métodos de tipo function foo() {}.
  • Comprueba si la clase (el código C) tiene una función (código C) get_method() y si lo ha invocado para dejar que la implementación de la clase decida.

Necesitarás lo último. Pero este get_method() no está "extendido" al código del script php, es decir, no hay forma de que get_method() llame a algún código de script php definido por el usuario (¿Y qué devolvería este código php?).

Así que la respuesta a mi mejor conocimiento es: No, no es posible (todavía?).

La implementación de ZEND_FUNCTION(method_exists) se puede encontrar en zend/zend_builtin_functions.c y creo que es bastante legible incluso si no conoce C sino PHP.

5

Eche un vistazo a is_callable().

Pero no, si el método __call() solo maneja algunos nombres, entonces necesitaría otra forma de verificar si la llamada tendrá éxito.

¿Puedo sugerir una interfaz con el método canCall($function), o algo así? Luego verifica si la clase implementa la interfaz. Si no lo hace, simplemente use is_callable().

+2

is_callable() devuelve automáticamente true si __call() está definido, lo que hace is_callable() undependable (ya que no garantiza que __call() satisfaga la solicitud) –

8

__call maneja llamadas a métodos que no existen. method_exists es un método de introspección que verifica la existencia de un método.

¿Cómo se puede determinar __call para manejar un método? Creo que debe lanzar una excepción manualmente en __call si no maneja su solicitud y captura la excepción en el código que de otra manera usaría method_exists. BadMethodCallException existe para este propósito.

+1

Parece que '__call' no tiene noción de" defectuoso ", por lo que parece que lanzar una 'NotImplementedException' (o similar) en el método __call sería la forma de hacerlo. –

1

estaría tentado de utilizar lo mejor method_exists en su función __call y throw un Exception Si esto falla y lo envuelve todo en un bloque en lugar de utilizar la función is_callabletrycatch.

1

Si está realmente seguro de que siempre tiene un _call de repliegue, puede hacerlo:

if (method_exists($this, $method_name) || method_exists($this, '__call')) { 
    // Call of the method 
}