2011-04-21 11 views
10

¿hay alguna forma en PHP para configurar el manejador de errores solo para espacios de nombres específicos? Estoy construyendo un pequeño marco y me gustaría poder probar todos los mensajes de error/advertencia/aviso dentro de su espacio de nombres configurando el controlador de error personalizado y lanzando excepciones con él. Los errores desencadenados fuera de este espacio de nombre específico deben comportarse de forma regular.Limitar el manejador de errores de PHP a los espacios de nombres específicos

¿Se puede hacer con PHP?

Gracias.

+2

No lo creo: no hay información sobre el espacio de nombres en los datos de retorno de 'debug_backtrace()' (basado en el cual puede decirle a su manejador de errores cómo reaccionar). Interesado para ver si surge algo. –

Respuesta

2

Disculpas por adelantado por no realmente probar esto antes de publicar:

El quinto parámetro (opcional), que PHP pasa a su método de tratamiento de errores (y que por lo general se ignora) es un $ contexto_err matriz que apunta a la tabla actual de símbolos PHP Mi idea es que si puede extraer el espacio de nombres de la parte posterior de una excepción propuesta por Rudie, entonces también es posible extraer información de espacio de nombres de manera similar a $ errcontext. Si eso es cierto, su manejador de errores puede verificar su propio espacio de nombres y "desaparecer" al devolver falso si el espacio de nombres actual no coincide con aquel para el que está diseñado el controlador de errores.

Además, los manejadores de errores se pueden "apilar", lo que significa que al menos en principio (si mi sugerencia para "mío" $ errcontext realmente funciona) puede establecer un manejador de errores por separado para cada espacio de nombres.

No estoy afirmando que este enfoque sea más "elegante" que las soluciones propuestas por Josh y Rudie, pero parece estar en línea con lo que estás tratando de hacer, que es imponer un tipo de restricción de alcance en su (s) controlador (es) de errores.

¡Buena suerte!

+0

Gracias, fue realmente útil. $ errcontext no era exactamente lo que esperaba, pero obtuve algunas buenas ideas. Definiré el controlador de errores dentro de un objeto, que tiene una pila de nombres de funciones de devolución de llamada almacenados en una matriz estática (ya que set_error_handler simplemente anula las funciones definidas previamente). Luego uso call_user_func para cada función y verifico los valores devueltos. Dentro de esas funciones voy a usar ideas combinadas de las respuestas de Rudie y Josh. De hecho, es una pena que no haya una implementación nativa (que yo sepa) para apilar controladores de errores. Es feo, caro ... funciona. – Mikk

+0

En realidad, set_error_handler() * no * anula los manejadores de errores previamente declarados - empuja a uno nuevo en la "pila", y el intérprete de PHP lo llama primero al manejar un error. Si sale su nuevo controlador de errores, no se llama a ninguno de los manejadores de errores restantes en la pila (por lo que es como si los hubiera descartado), pero si su manejador de errores devuelve el valor falso, se llama al siguiente controlador de error en la pila. OMI sería más limpio dejar que PHP maneje su "pila de funciones de devolución de llamada" de lo que sería cargarlas en una matriz, pero por supuesto eso podría funcionar. – Peter

0

¿Se puede hacer con PHP?

Se puede hacer bastante fácilmente, diría yo. Sin escribir el código, esto es lo que haría:

  1. Crear un bloque try/catch
  2. capturar todas las excepciones (\Exception)
  3. Encontrar la última clase llamada (en algún lugar $exception->getTrace())
  4. Esa clase tendrá su espacio de nombres en su nombre: some\name\space\Class
  5. uso dirname($namespace) para eliminar el nombre de la clase ("Class" en este caso)
  6. hacer w ualquiera sea que quiera con el resultado o volver a lanzar la excepción: throw $exception;

edición
Incluso los cierres tienen espacios de nombres:

namespace oele\boele; 

$fn = function() { 
    throw new \Exception; 
}; 

try { 
    $fn(); 
} 
catch (\Exception $ex) { 
    print_r($ex); 
} 

$ex->getTrace()[0]['function'] serán oele\boele\{closure}

edición
Lástima el trace array doesn No tiene una clave 'namespace' para cada elemento.

+0

Creo que el op preguntaba por 'set_error_handler()', por no tener que envolver todo en bloques try/catch gigantes – knittl

+0

Si se trata de un framework, la mayor parte debería 'estar' empaquetado en un gran bloque try/catch en FrontController de todos modos ... IMO – Rudie

+0

Sí, estaba pensando en la función set_error_handler(). La captura de su propia excepción personalizada no debe ser un problema. – Mikk

1

no he intentado hacer esto antes, así que me disculpo de antemano si esto no funciona (al menos puede hacerle pensar), pero así es como me gustaría tratar de lograr esto:

Desde su espacio de nombres va a ser parte de un marco global más amplio, quisiera que todas las clases en el marco extiendan una clase base (para esto, llamemos BaseClass). Dentro de esa clase crearía un método llamado errorHandler(). Dentro de esta función, usted haría lo que quiera por el manejo de su excepción (tal vez incluso lanzando una excepción).

Ahora que tiene esta funcionalidad, tenemos que averiguar cómo obtener esta función. Como todos los objetos de su espacio de nombres extienden BaseClass, todos tienen acceso a este método errorHandler(). Ahora dentro de su código puede usar los bloques try/catch normales para capturar las excepciones que suceden y, en lugar de usar el modelo de excepción estándar, en su lugar debería llamar $ this-> errorHander() (Ahora que lo pienso, puede que quiera poner algunos parámetros aquí, posiblemente la excepción que se obtiene de la declaración catch). Esto debería darle lo que necesita para las partes del código que espera que ocurran los problemas.

La siguiente parte que debemos averiguar es manejar las excepciones que no espera y cómo planea enrutarlas a través de este manejador de errores. Este es un poco más complicado porque esta solución se basa en un bloque try/catch en alguna parte. Dado que este es un marco, voy a suponer que todo se ejecuta a través de index.php o algún otro archivo de arranque (algo así como Zend Framework o similar). Si este es el caso, pondría su try/catch alrededor donde comience la eliminación del framework. Basado en la excepción que obtienes en el bloque catch, puedes decidir si quieres ejecutarlo a través del método errorHandler(). Tengo que administrar esta parte de alguna manera se siente un poco sucio y que debería haber una mejor manera de hacerlo (tal vez una vez que llegue más lejos se presentará una mejor solución).

Esperamos que esto lo ayude a avanzar en su proceso. Si alguien tiene una idea de cómo conseguir que la última parte no se sienta tan sucia, sería genial.

Cuestiones relacionadas