The (im)proper use of try..catch.
Delusion
Most examples of try..catch
operator you can find on the Net are something like this:
try {
$stmt = $dbh->prepare($sql);
$stmt->execute($data);
} catch (PDOException $e) {
die($e->getMessage());
}
Shamefully, PHP manual is especially bad at it, having such examples all over PDO and other extensions examples.
TL;DR
Never use try-catch for the basic error reporting. Just leave exceptions alone:
$stmt = $dbh->prepare($sql);
$stmt->execute();
Disclosure
Such a code is a result of a mere confusion. Look, what you actually have from it:
An error message being thrown right on the screen,
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'foo' at line 1
Looks exactly what you were looking for? Not quite.
- it appears on the screen unconditionally, revealing some system internals to a potential attacker when site goes live
- also it is scaring innocent user with strange message.
- also it is killing the script in the middle, so it may cause torn design (or no design at all) shown
- it is killing the script fatally, irrecoverably.
- it is showing only part of error info, making it sometimes difficult to identify the error for the programmer
- it is adding four lines of repeated code for the every query in the application, making it bloated and WET.
NONE of these things you actually want.
Clarification
As a matter of fact, you are writing this code only to be visually notified of the error, if it happened during development. The funny part is that for such a cause you need no extra code at all. I am not kidding. PHP is quite good with reporting errors, and need no extra assistance. If you leave your PDO code alone, adding no useless try..catch
stuff, an exception will be translated into a fatal error, and PHP will be happy to report this fatal error usual way, just like any other error message.
That's the point.
Unlike your unconditional approach, PHP will follow site-wide configuration options, set for the whole server. If you want error messages to be shown right on the screen, just set the proper option for this: display_errors
. That's all. In case of error, it will be revealed to you. Moreover, it will contain whole error message, including exact file name and line number where error occurred. And even more - a stack trace, which will help you to track down the code that actually caused the error:
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'foo' at line 1' in /srv/hosting/html/another_file.php:5
Stack trace:
#0 /srv/hosting/html/another_file.php(5): PDO->query('foo')
#1 /srv/hosting/html/pdo.php(23): demo()
#2 {main}
Here you can see the full error message you were depriving yourself from.
Let's closely examine it
- Fatal error: Uncaught exception part we can omit, nothing interesting here
- 'PDOException' with message 'SQLSTATE[42000] is telling us that it is not PDO throwing error at its whim, but just relaying to us an error message from mysql.
- Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'foo' at line 1' - the error message itself
- in /srv/hosting/html/another_file.php:5 - most important part. It points to the exact point where error occurred.
- Stack trace: - even more useful thing that reveals a chain of events that led to this particular error.
And all that treasure without a single extra line of code! Just with default PHP settings! Isn't it wonderful?
All right, but what about production environment? That's very interesting question. In fact, most PHP users consider themselves the only users of their site. And that custom of catching and echoing every error is a sure proof for that - it's intended for the programmer only but inconvenient for the users. While in reality sometimes sites go live, and require totally different error handling in this case.
To handle an error on a live site we actually need:
- log error for the programmer
- show a generic error page for the user
- send appropriate HTTP response code for the Search Engine
And again - PHP already can do it all for us! If we turn display_errors=off
, while log_errors= on
, PHP will do all the things automatically - log error, show error page and HTTP code. As of the custom error page, it is best to be handled by the web-server (ErrorDocument
for Apache and error_page
for Nginx).
— But I am doing it only for debugging purpose!!!
Well, you are doing it wrong. A programmer have to be notified of errors any time, no matter which mode is on.
Example
— But what if I want something more complex than just showing/logging?
In such a case you can setup a Custom Exception Handler like this
set_exception_handler('myExceptionHandler');
function myExceptionHandler($e)
{
header('HTTP/1.1 500 Internal Server Error', TRUE, 500);
error_log($e);
readfile ('500.html');
exit;
}
or, for a more general handling not only exceptions but all errors,
set_error_handler("myErrorHandler");
function myErrorHandler($errno, $errstr, $errfile, $errline)
{
error_log("$errstr in $errfile:$errline");
header('HTTP/1.1 500 Internal Server Error', TRUE, 500);
readfile("500.html");
exit;
}
written just once it will relieve you from writing handling code again and again.
— All right, but is here a case when try..catch can be useful?
Sure! Just use try..catch only if you going to handle the error itself. Say, there is a code to process uploaded images. An error in such processing is not a fatal one and can be handled - so, that's the right place for the try..catch!
try {
processUploadedImage($file);
} catch (Exception $e) {
$formHandlerErrors[] = "There is an error processing uploaded image";
}
In short, if your error is recoverable and you have a certain scenario to recover - then use try..catch.
Add a comment
Please refrain from sending spam or advertising of any sort.
Messages with hyperlinks will be pending for moderator's review.
Markdown is now supported:
>
before and an empty line after for a quote