Whoops! Errores de PHP para Cool Kids

Whoops es una pequeña biblioteca, disponible como un paquete Composer, que te ayuda a manejar errores y excepciones en tus proyectos PHP.

Fuera de la caja, obtiene una página de error elegante, intuitiva e informativa cada vez que algo va mal en su aplicación. Aún mejor, todo esto es un conjunto de herramientas muy sencillo, pero flexible, para tratar los errores de una manera que tenga sentido para lo que sea que esté haciendo..

Las principales características de la biblioteca son:

  • Página detallada e intuitiva para errores y excepciones.
  • Vista de código para todos los marcos
  • Céntrese en el análisis de errores / excepciones a través del uso de dispositivos intermedios / manejadores simples y personalizados
  • Soporte para peticiones JSON y AJAX.
  • Proveedores incluidos para los proyectos Silex y Zend a través de los proveedores incluidos, e incluidos como parte del núcleo de Laravel 4
  • Base de código limpia, compacta y probada, sin dependencias adicionales

Whoops logra esto a través de un sistema de manejadores apilados. Usted le dice a Whoops qué manejadores desea usar (puede elegir entre los manejadores incluidos o hacer los suyos propios), y si sucede algo, todos los manejadores reciben, en orden, una oportunidad de hacer algo, esto puede ser cualquier cosa, desde analizar el error (Whoops hace que sea más fácil extraer información significativa de un error o excepción), para mostrar pantallas de error útiles (como las integradas PrettyPageHandler, lo que le da la página de aspecto fresco en la imagen de arriba).

Vamos a intentarlo, primero, observando los aspectos básicos, y luego intentando construir nuestro propio controlador con Whoops y el marco de trabajo de Laravel. Para esta breve guía, asumiré que te sientes moderadamente cómodo con PHP y que has oído hablar de Composer. Si este no es el caso, lea sobre esto aquí en Nettuts+.


Instalando Whoops

Cree un directorio para su proyecto, cámbielo, cree un directorio compositor.json archivar con el requisito Whoops, e instalarlo. Whoops (a partir de la versión 1.0.5) no tiene dependencias, por lo que esto solo tomará un segundo.

 $ cd / path / to / your / project $ composer require filp / whoops 1. * $ install composer

Usando Whoops: Lo básico

Para ver esa elegante página de errores en acción, configuremos Whoops y aseguremos que algo se rompa al lanzar una excepción dentro de nuestro código. Crea un archivo dentro del directorio de tu proyecto; Para esta guía, digamos que se llama., index.php.

 $ cd / path / to / your / project $ your-favorite-editor index.php

Debido a que instalamos Whoops with Composer, y es compatible con PSR-0, todo lo que necesitamos hacer es requerir el autocargador Composer y estamos listos para comenzar a usar la biblioteca dentro de nuestro propio código!

 pushHandler (new Whoops \ Handler \ PrettyPageHandler ()); // Establezca Whoops como el controlador predeterminado de errores y excepciones utilizado por PHP: $ whoops-> register (); lanzar una nueva excepción RuntimeException ("Oopsie!"); ?>

Si ya tiene un servidor web en ejecución, continúe y acceda al archivo que acaba de crear. No olvide: si está utilizando PHP 5.4, puede aprovechar el servidor de desarrollo incorporado, de esta manera:

 $ cd / ruta / a / su / proyecto $ php -S localhost: 8080

Esto es lo que obtendrás:

Bastante limpio, ¿verdad? Los manejadores, ellos mismos, pueden exponer opciones para modificar o aumentar su comportamiento. Por ejemplo, entre otras cosas, puede establecer el título de la página de error predeterminada e incluso insertar información adicional:

 setPageTitle ("¡Está roto!"); // Establecer el título de la página $ errorPage-> setEditor ("sublime"); // Configurar el editor usado para el enlace "Abrir" $ errorPage-> addDataTable ("Información adicional", array ("stuff" => 123, "foo" => "bar", "useful-id" => "baloney ")); $ whoops-> pushHandler ($ errorPage); $ whoops-> register (); lanzar una nueva excepción RuntimeException ("Oopsie!"); ?>

Además, dado que este es simplemente un controlador Whoops regular, podemos mezclar y combinar con otros controladores para lograr resultados más dinámicos. Imaginemos que estás trabajando en un sitio web basado en AJAX + JSON. En este momento, si su aplicación fallara de alguna manera, obtendría un montón de HTML desagradable en el futuro, cuando esperaba a JSON. No es gran cosa:

 pushHandler (new Whoops \ Handler \ PrettyPageHandler ()); $ whoops-> pushHandler (new Whoops \ Handler \ JsonResponseHandler ()); $ whoops-> register (); lanzar una nueva excepción RuntimeException ("Oopsie!");

Eso es. Ahora, si algo falla durante una solicitud AJAX, Whoops responderá con una respuesta JSON que detalla el error. Si NO es una solicitud de AJAX, continuará viendo la página de error regular. Si ocurre un error, Whoops se filtrará a través de cada uno de los manejadores registrados (comenzando en el último manejador que se registrará), y les dará la oportunidad de analizar, modificar y responder a la solicitud..

Ahora que tiene una idea general de cómo funciona Whoops, vamos a intentar construir nuestro propio controlador con Whoops y el marco Laravel 4..


Whoops y Laravel 4

Laravel 4 agrupa a Whoops como un controlador de excepción central, habilitado de forma predeterminada en el modo de desarrollo, que incluye un esquema de color personalizado por Dayle Rees:

Si aún no ha instalado Laravel, vaya y siga los pasos de instalación. Laravel tiene una amplia cobertura en Nettuts + y Tuts + Premium, por lo que encontrarás mucho entrenamiento aquí, si deseas profundizar más.

Para los próximos pasos, asumiré que te sientes un poco cómodo con los conceptos básicos de Laravel 4. Sin embargo, aunque no lo estés, debería ser fácil de seguir..

Si está en modo de desarrollo (depuración), Whoops está disponible a través del contenedor IoC como gritos, y pre-establecido con uno de los dos controladores: PrettyPageHandler o JsonResponseHandler, como whoops.handler (los mismos dos de los que acabamos de hablar). Ambos de estos controladores exponen métodos adicionales útiles, como ha visto anteriormente con el PrettyPageHandler. Al acceder a estos servicios, podemos comenzar a personalizar nuestra experiencia de Whoops dentro del marco.

Por simplicidad, en su app / route.php archivo, vamos a enganchar en el servicio Whoops y establecer un título de página personalizado para nuestras páginas de error:

 setPageTitle ("Houston, tenemos un problema!"); // Establezca el enlace "abrir:" para los archivos en nuestro editor de elección: $ whoopsDisplayHandler-> setEditor ("sublime");  Route :: get ('/', function () // Forzar la ejecución para que falle al lanzar una excepción: lanza la nueva RuntimeException ("Oopsie!");); ?>

Propina: Whoops admite algunos editores de forma predeterminada y le permite implementar el soporte para el suyo como desee. Lea más sobre esto aquí.

Si ahora accede a su aplicación Laravel, recibirá un mensaje de error con el título de su página personalizada. Si hace clic en la ruta del archivo sobre el cuadro de código, debería abrir el archivo de referencia directamente en su editor o IDE de su elección. ¿Cuan genial es eso? Además, dado que podemos alcanzar el controlador ya configurado por el núcleo de Laravel, podemos utilizar las otras características que hemos aprendido anteriormente. Por ejemplo, podemos agregar tablas personalizadas (con PrettyPageHandler :: addDataTable) Con información útil sobre nuestra aplicación..

Vamos a ver un ejemplo más. Este será nuestro primer intento de escribir nuestro propio controlador personalizado. Queremos obtener todos los marcos de pila para una excepción y eliminar todo lo que no sea parte de nuestro código de aplicación. Suena bastante simple, cierto?

 pushHandler (function ($ exception, $ exceptionInspector, $ runInstance) // Obtenga la colección de marcos de pila para la excepción actual: $ frames = $ exceptionInspector-> getFrames (); // Filtre los marcos existentes para que solo guardemos los que están dentro la aplicación / carpeta $ marcos-> filtro (función ($ marco) $ filePath = $ marco-> getFile (); // Coincidir con cualquier ruta de archivo que contenga / app / ... return preg_match ("/ \ / app \ /.+ / i ", $ filePath);); return Handler :: DONE;);  Route :: get ('/', function () // Forzar la ejecución para que falle al lanzar una excepción: lanza una nueva RuntimeException ("Oopsie!");); ?>

Propina: En realidad no tienes que volver Handler :: DONE - Esto sirve solo para un propósito semántico. Si desea que Whoops deje de ejecutar cualquier controlador adicional después del suyo, escriba controlador de devolución :: LAST_HANDLER. Si desea que Whoops salga de la ejecución del script después de su controlador, controlador de devolución :: SALIR.

Se puede ver que es muy conciso. Whoops \ Runes pushHandler el método acepta un cierre que recibe hasta tres argumentos: el objeto de excepción, un inspector de excepciones, que expone algunos métodos de utilidad a, usted lo adivinó, inspecciona las excepciones y la Whoops \ Run instancia que capturó la excepción. A través de este controlador, utilizamos el inspector de excepciones para extraer los marcos de la pila, todo dentro de un ordenado FrameCollection objeto:

 getFrames (); // # => Whoops \ Exception \ FrameCollection; cuenta ($ frames); # => int foreach ($ frames as $ frame) get_class ($ frame); // # => Whoops \ Exception \ Frame print $ frame-> getFile (). ":". $ frame-> getLine (). "\norte"; # => "/path/to/file.php:123"?>

Propina: Whoops convierte internamente los cierres a un manejador especial: Whoops \ Handler \ CallbackHandler.

Puede contar, iterar, mapear y filtrar los contenidos de esta clase, con el aspecto interesante pero importante de que las operaciones de mapeo y filtro mutan el objeto en el lugar. Esto significa que ambas operaciones modifican la instancia original directamente, en lugar de crear una nueva colección. ¿Cómo es esto importante? Significa que los manejadores pueden realizar cambios más fácilmente que se propagan hacia abajo a todos los otros manejadores de la pila. Esto es exactamente lo que hicimos con nuestro simple controlador arriba. Si ahora vuelve a ejecutar el script, verá que obtenemos una lista más corta de marcos de pila, solo con respecto al código que reside en nuestro directorio de aplicaciones.

En cuanto al objeto Frame, sí mismo (Whoops \ Exception \ Frame), expone un conjunto de métodos para recopilar información sobre el contenido del marco (la ruta del archivo, el número de línea, el método o la llamada a la función, el nombre de la clase, etc.) y los métodos que le permiten adjuntar comentarios a marcos de pila individuales. Un comentario de marco es una característica útil en Whoops que permite a los manejadores proporcionar información adicional que recopilan de una excepción al adjuntar notas directamente a marcos individuales en la pila. Manejadores como el PrettyPageHandler, por ejemplo, puede recopilar esos comentarios y mostrarlos junto con la ruta del archivo del marco y el número de línea.

 pushHandler (function ($ exception, $ exceptionInspector, $ runInstance) foreach ($ exceptionInspector-> getFrames () as $ i => $ frame) $ frame-> addComment ("Este es el número de cuadro $ i");  return Handler :: DONE;); ?>

Los comentarios de marco también pueden recibir un segundo alcance argumento. Si tiene varios manejadores personalizados, puede, por ejemplo, filtrar los comentarios de marco por este argumento para recopilar solo la información que le interesa.

 getFrames (); foreach ($ frames as $ frame) // ¿Estaba este frame dentro de una clase de controlador? (termina en Controlador) $ className = $ frame-> getClass (); if (substr ($ className, -10) == "Controller") $ frame-> addComment ("Este frame está dentro de un controlador: $ className", "controller-error");  // Más adelante, en otro controlador, obtenga todos los comentarios dentro del alcance de 'controller-errors': $ controllerErrors = $ frame-> getComments ("controller-errors"); // # => array?>

También de interés, el PrettyPageHandler naturalmente, HTML escapa a los comentarios del marco antes de mostrarlos, pero capturará de forma inteligente los URI en el cuerpo del comentario y los convertirá en elementos de anclaje en los que se puede hacer clic. ¿Desea vincular marcos a la documentación o a los repositorios de GitHub? Es bastante fácil; vamos a crear nuestra propia clase de controlador para este ejemplo.

Propina: El uso de su propia clase en lugar de un cierre le brinda cierto control adicional sobre su manejador, sin mencionar que hace que sea más fácil cubrirlo con pruebas automatizadas. Sus clases de manejador personalizado deben implementar el Whoops \ Handler \ HandlerInterface interfaz, pero en su lugar puede simplemente extender el Whoops \ Handler \ Handler clase, y poner en práctica los desaparecidos encargarse de método, como se muestra en el siguiente ejemplo.

 getInspector () -> getFrames (); foreach ($ frames as $ frame) $ file = $ frame-> getFile (); $ line = $ frame-> getLine (); // Es posible que algunos marcos no tengan una ruta de acceso al archivo, por ejemplo, si ocurrió dentro de // un Cierre, por lo que tendremos que verificarlo: si (! $ File) continúa; // Verifique si la ruta del archivo para este marco estaba dentro del directorio laravel / framework //, dentro del directorio Composer vendor /, y use una captura de expresiones regulares // para extraer solo las partes que queremos: if (preg_match ("/ \ / proveedor \ / laravel \ / framework \ / (. +) $ / ", $ archivo, $ coincidencias)) $ ruta = $ coincidencias [1]; // La primera coincidencia es la ruta completa, la segunda es nuestra captura $ url = "$ this-> repoBase / $ ruta"; // También podemos enlazar directamente a un número de línea, si lo tenemos. Github // apoya esto agregando #L hasta el final de la URL: if ($ line! == null) $ url. = "#L $ line";  $ frame-> addComment ($ url, "github-linker");  return Handler :: DONE; ?>

Eso es todo, en lo que respecta a nuestro controlador. Coloque esa clase en algún lugar de su proyecto, y todo lo que queda por hacer es habilitar y probar:

 pushHandler (new LaravelGithubLinkHandler ()); //…?>

Con solo un puñado de líneas de código, hemos agregado una capa adicional de funcionalidad (posiblemente inútil, pero bueno, es un ejemplo) a nuestras páginas de error. Aquí hay algunas ideas adicionales, si estás buscando un desafío:

  • Empaque su controlador de errores personalizado como proveedor de servicios Laravel.
  • ¿Estás utilizando Git para gestionar tu proyecto? Construye un controlador personalizado que se enganche en git-culpa para determinar quién fue la última persona en tocar ese archivo que sigue lanzando una excepción (y gritándoles), directamente desde la página de error.
  • Si te sientes valiente, usa PHP-Parser de nikic para analizar el código problemático y proporciona sugerencias para corregirlo (te prometo que no es tan complicado como parece).

Pensamientos finales

Espero que esta breve guía le haya ayudado a comprender mejor el tipo de posibilidades que esta biblioteca habilita en sus proyectos diarios. Para más información, consulte la documentación completa de la API..

Whoops es agnóstico al marco, ligero y, creo, bastante poderoso en su simplicidad y se enfoca en mezclar y combinar herramientas pequeñas. También es de código abierto y está abierto a sugerencias y mejoras. Si desea contribuir o informar un error, diríjase al repositorio oficial!