A Symfony filter to catch all of one’s own exceptions
I am intrigued by Felix De Vliegher’s suggestion for a single filter that catches all of one’s exceptions in Symfony:
class ExceptionCatcherFilter extends sfFilter
{
public function execute($filterChain)
{
if (sfConfig::get(’app_exceptionCatcherFilter’)) {
try {
$filterChain->execute();
} catch (sfStopException $e) {
// This is an internally used symfony exception and shouldn’t be blocked
throw $e;
} catch (Exception $e) {
// Do something with the exception, other than just throwing it
}
} else {
$filterChain->execute();
}
}
}
Generally, I dislike this style of programming, where all errors are funneled through a central well. This style of programming is the one advocated by Anders Hejlsberg (inventor of the C# language):
There’s a bottom level exception handler around their message loop. That handler is just going to bring up a dialog that says what went wrong and continue. The programmers protect their code by writing try finally’s everywhere, so they’ll back out correctly if an exception occurs, but they’re not actually interested in handling the exceptions.
The throws clause, at least the way it’s implemented in Java, doesn’t necessarily force you to handle the exceptions, but if you don’t handle them, it forces you to acknowledge precisely which exceptions might pass through. It requires you to either catch declared exceptions or put them in your own throws clause. To work around this requirement, people do ridiculous things. For example, they decorate every method with, “throws Exception.” That just completely defeats the feature, and you just made the programmer write more gobbledy gunk. That doesn’t help anybody.
…It is funny how people think that the important thing about exceptions is handling them. That is not the important thing about exceptions. In a well-written application there’s a ratio of ten to one, in my opinion, of try finally to try catch. Or in C#, using statements, which are like try finally.
…In the finally, you protect yourself against the exceptions, but you don’t actually handle them. Error handling you put somewhere else. Surely in any kind of event-driven application like any kind of modern UI, you typically put an exception handler around your main message pump, and you just handle exceptions as they fall out that way. But you make sure you protect yourself all the way out by deallocating any resources you’ve grabbed, and so forth. You clean up after yourself, so you’re always in a consistent state. You don’t want a program where in 100 different places you handle exceptions and pop up error dialogs. What if you want to change the way you put up that dialog box? That’s just terrible. The exception handling should be centralized, and you should just protect yourself as the exceptions propagate out to the handler.
In contrast, I have always preferred the style advocated by James Gosling (inventor of the Java language), and the style preferred by Bill Venners, as articulated in this interview:
Bill Venners: I do catch exceptions in an outer loop sometimes. But most times my catch clauses tend to be spread around the program. I find that catch clauses usually have a natural home—the method that has enough contextual knowledge to know how to deal with the exception. How would you recommend people organize their catch clauses?
James Gosling: I tend to do catches much more frequently than Anders would have you do, because the knowledge of the situation is always fairly localized. When you try to open a file and it’s not there, you’re coping strategy is really determined by what you were going for. Some guy miles away isn’t going to know what to do. The code that tried to open the file knows what to do, whether it be trying a backup file, looking in a different directory, or asking the user for another filename.
Having one big catch clause on the outside really only works if your exception handling philosophy is simply to die. If you have an event loop, you can maybe cause that one event to just be tossed. If you have a plugin architecture, the enclosing environment could respond to a failure in the plugin by disabling it—like an app server deciding to disable a servlet if it sees failures. But if you’re not doing an event driven program or plugins, there isn’t an outside place where you can take big hunks of functionality and saw them off. On the other hand, typically you should have last ditch try catch blocks. If you’re writing a web server, for example, it’s a good thing to put a last ditch try catch block around processing a request. But pretty much all that a try catch block like that can do is blow the request away. There’s no ability to respond gracefully. There’s no ability to take account of local context to cope and adapt, which is really one of the key hallmarks of truly reliable software.
The key sentence is “Having one big catch clause on the outside really only works if your exception handling philosophy is simply to die.” Handling exceptions close to where they happen allows you to use variables that are within the current context to try to rescue the situation.
All the same, Felix De Vliegher’s idea is a wonderfully clean way to proceed with a Hejlsberg type of exception handling.