Whoops! PHP Errors for Cool Kids

Whoops is a small library, available as a Composer package, that helps you handle errors and exceptions across your PHP projects.

Out of the box, you get a sleek, intuitive and informative error page each time something goes pants-up in your application. Even better, under all that is a very straight-forward, but flexible, toolset for dealing with errors in a way that makes sense for whatever it is that you're doing.

The library's main features are:

  • Detailed and intuitive page for errors and exceptions
  • Code view for all frames
  • Focus on error/exception analysis through the use of custom, simple middle-ware/handlers
  • Support for JSON and AJAX requests
  • Included providers for Silex and Zend projects through the bundled providers, and included as part of the Laravel 4 core
  • Clean, compact, and tested code-base, with no extra dependencies
image

Whoops achieves this through a system of stacked handlers. You tell Whoops which handlers you want to use (you can choose from the included handlers or make your own), and if something happens, all the handlers are given, in order, a chance do to something - this can be anything from analyzing the error (Whoops makes it easier to extract meaningful information from an error or exception), to displaying helpful error screens (like the built-in PrettyPageHandler, which gives you the cool looking page pictured above).

Let's give it a try, first, by looking at the basics, and then by having a go at building our own handler with Whoops and the Laravel framework. For this short guide, I'll assume that you're moderately comfortable with PHP, and that you've heard of Composer. If this is not the case, read-up on it here at Nettuts+.


Installing Whoops

Create a directory for your project, change into it, create a composer.json file with the Whoops requirement, and install it. Whoops (as of version 1.0.5) has no dependencies, so this will only take a second.


Using Whoops: The Basics

To see that sleek error page in action, let's setup Whoops and ensure that something breaks by throwing an exception within our code. Create a file within your project's directory; for this guide, let's say that it's called, index.php.

Because we installed Whoops with Composer, and it is PSR-0 compliant, all we need to do is require the Composer autoloader and we're ready to start using the library within our own code!

If you already have a web-server running, go ahead and access the file that you just created. Don't forget: if you're using PHP 5.4, you can leverage the built-in development server, like so:

This is what you'll get:

image

Pretty neat, right? Handlers, themselves, can expose options to modify or augment their behavior. For example, among other things, you can set the title of the default error page, and even insert extra information:

image

Also, since this is simply a regular Whoops handler, we can mix-and-match with other handlers to achieve more dynamic results. Let's imagine that you're working on an AJAX+JSON-driven website. Right now, if your application were to fail somehow, you would get a bunch of nasty HTML coming down the pipe, when you were expecting JSON. No big deal:

That's it. Now, if something fails during an AJAX request, Whoops will respond with a JSON response detailing the error. If it's NOT an AJAX request, you will continue to see the regular error page. If an error ocurrs, Whoops will filter through each of the registered handlers (starting at the last handler to be registered), and give them a chance to analyze, modify and respond to the request.

Now that you have a general idea of how Whoops works, let's have a go at building our own handler with Whoops and the Laravel 4 framework.


Whoops and Laravel 4

Laravel 4 bundles Whoops as a core exception handler, enabled by default in development mode, including a custom color-scheme by Dayle Rees:

image

If you haven't installed Laravel yet, head on over and follow the installation steps. Laravel is covered extensively on Nettuts+ and Tuts+ Premium, so you'll find plenty of training here, if you'd like to dig in further.

For the next steps, I'll assume that you are somewhat comfortable with the basics of Laravel 4. However, even if you aren't, it should still be easy to follow.

If you're in development (debug) mode, Whoops is available through the IoC container as whoops, and pre-set with one of two handlers: PrettyPageHandler or JsonResponseHandler, as whoops.handler (the same two we just talked about). Both of these handlers expose useful additional methods, as you've seen above with the PrettyPageHandler. By accessing these services, we can start customizing our Whoops experience within the framework.

For simplicity's sake, in your app/routes.php file, let's hook into the Whoops service and set a custom page title for our error pages:

Tip: Whoops supports a few editors by default, and allows you to implement support for your own as you wish. Read more about it here.

If you now access your Laravel application, you'll be greeted with an error message with your custom page title. If you click the file path above the code box, it should open the referenced file right in your editor or IDE of choice. How cool is that? Also, since we can reach the handler already setup by the Laravel core, we can put to use the other features we've learned about above. For example, we can add custom tables (with PrettyPageHandler::addDataTable) with useful information about our application.

Let's have a go at one more example. This will be our first attempt at writing our own custom handler. We want to get all the stack frames for an exception, and remove anything that's not part of our application code. Sounds simple enough, right?

Tip: You don't actually have to return Handler::DONE - this serves only a semantic purpose. If you want Whoops to stop running any extra handlers after yours, write return Handler::LAST_HANDLER. If you want Whoops to exit the script execution after your handler, return Handler::QUIT.

You can see that it's remarkably concise. Whoops\Run's pushHandler method accepts a closure that receives up to three arguments: the exception object, an exception inspector, which exposes some utility methods to, you guessed it, inspect exceptions, and the Whoops\Run instance that captured the exception. Through this handler, we use the exception inspector to extract the stack frames, all within a neat FrameCollection object:

Tip: Whoops internally converts closures to a special handler: Whoops\Handler\CallbackHandler.

You can count, iterate, map and filter the contents of this class, with the interesting but important aspect that the map and filter operations mutate the object in-place. This means that both of these operations modify the original instance directly, instead of creating a new collection. How is this important? It means handlers can more easily perform changes that propagate downwards to all the other handlers in the stack. This is exactly what we did with our simple handler above. If you now run the script again, you'll see that we get a shorter list of stack frames, only concerning the code living within our application directory.

image

As for the Frame object, itself (Whoops\Exception\Frame), it exposes a set of methods to gather information about the frame contents (the file path, line number, the method or function call, class name, etc,), and methods that allow you to attach comments to individual stack frames. A Frame comment is a useful feature in Whoops that allows handlers to provide additional information that they gather from an exception by attaching notes directly to individual frames in the stack. Handlers like the PrettyPageHandler, for example, can then gather those comments and display them along with the frame's file path and line number.

image

Frame comments may also receive a second scope argument. If you have multiple custom handlers, you can, for example, filter frame comments by this argument to gather only the information that you care about.

Also of interest, the PrettyPageHandler naturally HTML-escapes the frame comments before displaying them, but will intelligently capture URIs in the comment's body and convert them to clickable anchor elements. Want to link frames to documentation, or to GitHub repositories? It's easy enough; let's create our own handler class for this example.

Tip: Using your own class instead of a closure provides you with some extra control over your handler - not to mention making it easier to cover with automated tests. Your custom handler classes must implement the Whoops\Handler\HandlerInterface interface, but you may instead simply extend the Whoops\Handler\Handler class, and implement the missing handle method, as shown in the example below.

That's it, as far as our handler goes. Put that class somewhere in your project, and all that's left to do is enable and try it out:

image

With only a handful of lines of code, we've added an extra layer of (possibly useless, but hey, it's an example) functionality to our error pages. Here are a few extra ideas, if you're looking for a challenge:

  • Package your custom error handler as a Laravel service provider.
  • Are you using Git to manage your project? Build a custom handler that hooks into git-blame to determine who the last person to touch that file that keeps throwing an exception (and yell at them) was, directly from the error page.
  • If you're feeling brave, use nikic's PHP-Parser to analyze the troublesome code, and provide suggestions for fixes (I promise it's not as complicated as it sounds).

Final Thoughts

I hope that this short guide has helped you gain an understanding of the sort of possibilities that this library enables in your every-day projects. For more information, refer to the complete API documentation.

Whoops is framework-agnostic, light-weight and, I believe, quite powerful in its simplicity and focus on mix-and-matching small tools. It's also open-source and open to suggestions and improvements. If you'd like to contribute or report a bug, head to the official repository!

Tags:

Comments

Related Articles