Thanks to everyone for your comments. It seems my own intuition on this more or less agrees with what everyone was saying. The code I committed before this thread took off was more or less going in the right direction, although there are some places where exceptions have been used as a stopgap, and they should probably be migrated to use return values at some stage.
Gregory Szorc wrote:
If something wrong happens in a function, you call trigger_error() and pass an error message and severity constant. I override PHP's error handler with set_error_handler(). In my custom error handler function, if the error severity is great enough to warrant program termination, I throw an exception. If not, the error simply gets logged or handled in its own way. Basically, I use exceptions to terminate program execution and return types to alter program execution.
The basic problem I was facing was that the original MediaWiki code used program termination in patently inappropriate places. The best and most commonly used error page function, OutputPage::errorpage(), exited the program after outputting its text. The task at hand was to remove all of these exit() calls, to support applications such as an HTTP server embedded in MediaWiki. Also, customised handling of unexpected database query errors was desired, and exceptions were the obvious means to do that.
I replaced most of the program terminations in error exits with a return to normal program flow. In certain cases where it looked a bit difficult, I used an exception instead, but that can be fixed at a later date.
For unexpected code branches which appear to be unreachable through ordinary user action, the previous code exited with a backtrace; I replaced these with an exception throw to produce similar behaviour.
For the benefit of extensions and other unmigrated code, the old interfaces such as OutputPage::errorpage() and wfDebugDieBacktrace() simulate the old behaviour by throwing an exception, thus avoiding an unexpected return of control.
-- Tim Starling