I came across some code recently that used a custom error handler to turn any PHP errors into an generalized application exception. A custom exception handler was also defined that would log the exception if it was within a particular error code range. Example:
class AppException extends Exception
{
}
function error_handler($errno, $errstr, $errfile, $errline)
{
throw new AppException($errstr, $errno);
}
function exception_handler($exception)
{
$min = ...;
$max = ...;
if ($exception->getCode() >= $min && $exception->getCode() <= $max)
{
// log exception
}
}
set_error_handler('error_handler');
set_exception_handler('exception_handler');
$a[1]; // throws exception
The problem is that I saw things like:
try
{
do_something();
}
catch (AppException $exception)
{
}
Which implies that there is no distinction between actual programming errors and “Exceptional” behavior. Upon further digging, I came across parts of the code that were designed around the idea that PHP errors represented “Exceptional” behavior such as:
...
function my_function($param1, $param2)
{
// do something great
}
try
{
my_function('only_one_param');
}
catch (AppException $exception)
{
}
Which ends up obfuscating errors and the design of the application’s interface.
What is your opinion on handling errors this way? Is it worth turning PHP’s native errors into exceptions? What do you do in situations like the above where a codebase is designed around this idea?
Personally, I do this all the time. The only difference is that in my
error_handlerfunction, I check to see if the error is anE_NOTICEfirst, and only throw if it is not (I log the notice anyway)…I would change the
AppExceptionto something that extendsErrorException… Something like:PhpRuntimeErrorException extends ErrorExceptionwhich you ONLY use for PHP errors… The reason is so that it’s more readable (it’s easier to tell what aPhpRuntimeErrorExceptionis without needing to figure out where it’s thrown). The other reason, is that theErrorExceptionwill store the generating line/file/etc information, where it would not be stored elsewhere (since the backtrace starts from thethrowline)…So, then you can “try” code like this:
I also make my default exception handler generate a 500 server error page. That’s because any exceptions should be caught, and if they were not, it really is a server error…
Just my experience and opinion…