Which PDO methods throw exceptions? - php

When establishing a new PDO db handler, I've got to wrap everything into a try-catch to prevent an error message that would print all db access data to the user.
But how about all the other methods like exec(), for example? Must I wrap all of these into a try-catch block? At which point is the PHP documentation telling that an method throws an exception?

First of all, you can set how errors are dealt with by PDO, using the PDO::setAttribute method, to set the PDO::ATTR_ERRMODE (error reporting) option.
In particular, it is possible to configure PDO so it throws exceptions when there's an error, instead of reporting an "error" -- that's what I generally do.
Then, when a method can throw an exception, it should be indicated in it's documentation -- generaly, it's in the "Return value" section.
For instance, PDO::prepare can throw an exception -- depending on error reporting (see what I wrote just before) :
If the database server cannot
successfully prepare the statement,
PDO::prepare() returns FALSE or
emits PDOException (depending on
error handling).
As a sidenote : if you find a function / method that throws an exception, and it's not indicated in its documentation, it might be a good idea to create a bug report (see http://bugs.php.net/ ), so that problem is corrected ;-)
(Errors / mistakes / missing informations in the documentation are treated via the bug-tracker, like any other bug)

You can see if the method throws exceptions by looking at the manual.
If you look at the manual for __construct you'll see at the bottom under Errors/Exceptions that it throws an exception.

Related

Is there any way to make PDO exceptions be caught by default?

I use PDO over my webapp. I use this simple code to ensure that the query is executed successfully & handle the error if it fails
$stmt = // MySQL query;
if($stmt->execute()){
// Do something
} else {
// Handle the error
echo 'some error';
}
It doesn't work because any PDO uncaught exception e.g (duplicate entry primary key) is a fatal error so the PHP script stop execution. I know TRY/CATCH solve this case but i've tons of queries, It'd take long time to use try/catch on each query.
My Question
Is there any way to make PDO exceptions be caught by default to be generalize over my webapp ?
I found the best practice to handle PDO uncaught exception without using try/catch after reading this
What-is-SetAttribute-PDO-ATTR_ERRMODE ?
1 - SET attribute PDO::ATTR_ERRMODE ----- > PDO::ERRMODE_WARNING
PDO::ERRMODE_WARNING // issue warning and continue executing the script
2 - Check error log file of your apache to determine the error
IMP NOTE :
Do this practice only if you already handle errors through your code e.g (storing the php file name and line of the error in database).
You can handle warning by using function error_reporting()

Throwing custom exceptions without messages

I haven't uset custom exceptions before, and now it appears that I might need them but I'm not sure I understood correctly how are they supposed to be used.
Say I have a custom exception like this:
class not_found_exception extends exception{ }
Then I have a bunch of request handler functions (I think they are called controllers in the wild). And each function can throw different types of exceptions. If the URL doesn't match it throws my custom exception, the script will catch that type of exception and skip to next request handler if it's caught. But other types of exception are not supposed to be caught because they mean that the url matches but there's some other error that should be displayed.
The thing is that my custom exception doesn't need an error message because it would not show up anywhere because its supposed to be caught, but other exceptions do. So is it ok to just throw an empty not_found_exception exception?
The short answer is simply: yes. That would be ok.
For further information about best-practices regarding Exception I'll refer you to this blog. It may be written for .NET but the theories can still be applied to PHP.
https://blogs.msdn.microsoft.com/kcwalina/2007/01/30/how-to-design-exception-hierarchies/

Can PDO methods fail and not throw PDOException?

I'm tweaking a legacy database class written for PHP/5.2 that was designed to connect to MySQL and hide all errors. I've configured the PDO instance to throw exceptions:
new PDO($dsn, $user, $pass, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION))
Now I need to adjust my code accordingly to handle the case where functions can throw an exception where they wouldn't before so I head to the manual.
In some cases the manual is explicit, e.g. PDO::prepare:
If the database server successfully prepares the statement,
PDO::prepare() returns a PDOStatement object. If the database server
cannot successfully prepare the statement, PDO::prepare() returns
FALSE or emits PDOException (depending on error handling).
In other cases it's kind of vague, e.g. PDO::commit:
Returns TRUE on success or FALSE on failure. Throws a PDOException
if there is no active transaction.
(Can it fail for some other reason and simply return false?)
And there're cases when exceptions are not even mentioned, e.g. PDO::bindValue:
Returns TRUE on success or FALSE on failure.
... even though it's clear to verify that it does throw PDOException on error (at least, on certain errors).
Do I still need to check the return value of methods that return false on error when the manual doesn't say otherwise?
No, when you set PDO::ERRMODE_EXCEPTION there will be always exception for any errors
When you have exceptions enabled and there is an error happening in your code, the code directly stops executing from that function, so it wont return anything.
So to be blund, you don't need to check the return values but if you don't you cannot error anything specific and you would rely fully on PDO to error correctly.
When I created my database system, I take advantage of both if I see an error upcoming, I throw it myself instead. For example $pdo->prepare('') is very much valid but will error upon binding.
Then there are other functions such as fetch that wont error if there are no results in the database, not checking the results from that would be silly.
Now for committing to fail, I believe there is 1 scenario that would cause it to return false without throwing an exception and that is when the connection to the server drops after connecting to the database and before calling PDO::commit, quite good to know if you have a remote database server.
So to answer your question, yes it can fail without throwing an exception, but its timing has to be very specific even more so if you have a local database.
Try this one
try {
$db = new PDO("mysql:host=localhost;dbname=dbname", "username", "password");
}catch( PDOException $Exception ) { $Exception->getMessage( ) ; }

postgres php exception handling

I have seen this question asked before on SO, and none of the answers seem to be complete. So please...
I have code using PDO and PDOStatement. It was originally written to work without exceptions, and I'm converting it to work with.
My simple questions are:
Are there any circumstances in which it is useful or necessary to continue to check the return value of functions for FALSE ( when this means "failure" ), or can I simply execute the method and assume that all kinds of failure will trigger an exception? I saw an example in an answer where someone was recommended to use BOTH try-catch AND to test the return value for FALSE - which, it is IS actually necessary, makes for some very ugly code.
Is there a proper list of which methods may, and which can never, throw an exception? I have seen answers which say "if you find we haven't documented an exception we throw, raise a bug", but that's not altogether helpful. I have seen statements that "the manual page says when an exception can be thrown", but the PDO::query and PDOStatement::execute pages make no mention of exceptions - which surely can't be true ... can it? Essentially I'd like to know whether prepare, bind[things], fetch[all], execute and a few others may or will never, throw stuff.
I don't feel I'm asking the earth, and if I have to I could look at the code, but surely the manual documentation on this should be rock solid.
[edit to add an example]
I now find myself with code blocks like this - I would like to simplify it by removing the test of the return value, but I cannot convince myself that it is correct. Other blocks use execute() and so on.
try {
/* I do not know whether beginTransaction throws an exception when it would otherwise return FALSE.
* If it does then checking the return value is spurious, and the code cam be simplified.
*/
if (FALSE == $customerDb->beginTransaction()) {
Log::add("Database begin transaction failed.",
Log::ERROR);
throw new Exception("Failed to begin a transaction.");
}
} catch (PDOException $e) {
/* The documentation does not mention the possibility of
* beginTransaction() throwing any exception,
* even when we have configured all the other functions to do so.
*/
Log::add("Database begin transaction threw an exception: " . $e->getMessage(),
Log::ERROR);
throw new Exception("Begin transaction threw an exception.");
}
There is three error handling strategies, ERRMODE_SILENT (the default one), ERRMODE_WARNING and ERRMODE_EXCEPTION. Only the last one make PDO throw exceptions if errors occurs, so except if you tell PDO explicitly to run in exception mode with:
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
It will not throw any exception except for PDO:__construct() which will throw an exception if the connection fails, whatever the value of PDO::ATTR_ERRMODE.
From the doc:
PDO::__construct() will always throw a PDOException if the connection
fails regardless of which PDO::ATTR_ERRMODE is currently set. Uncaught
Exceptions are fatal.
I suggest you to read the documentation - it's pretty clear how PDO handle errors.
Update
In your code sample, the exception will never be catched as you typed your catch block exception to PDO_Exception and you're throwing an Exception - which is the lower exception type level. If you want to catch all exceptions type, cast your catch parameter to Exception - currently your catch block capture only PDOException.
That being said, let's focus on the confusion you have about exceptions. There is no mysterious exceptions being thrown when in ERRMODE_SILENT or ERRMODE_WARNING, except the one from the PDO controller - which is documented. People telling otherwise are probably working in a PDO environment they don't really know / control - like a framework who use PDO but throw its own exceptions for queries, or changing the ATTR_ERRMODE in specific cases. I suggest you to focus less on the discussion under docs (as sometimes there could be interesting stuffs in it, most of the time it's comments from confused people) and focus more on the docs itself.
Let's be clear about what happen with errors in PDO.
An error occurs. If it happens in the PDO controller, an exception will be thrown and all next steps will be ignored.
The error will be standardized according to the SQL-92 standard (see this link for all the return codes that exists). From the doc :
PDO standardizes on using SQL-92 SQLSTATE error code strings; individual PDO drivers are responsible for mapping their native codes to the appropriate SQLSTATE codes.
PDO check for the ATTR_ERMODE attribute to know how it should handle this error.
ERRMODE_SILENT (the default mode)
The error will not be reported, so you'll need to check for the return of the PDO functions for false and check the PDO::errorCode(), PDO::errorInfo() or PDOStatement::errorCode(), PDOStatement::errorInfo() depending of the object you're using to get the error details.
ERRMODE_WARNING
Same as ERRMODE_SILENT but an E_WARNING PHP error will be thrown. Could be usefull for developpment, but you still need to check the function returns for false.
ERRMODE_EXCEPTION
A PDO_Exception will be thrown. There will be no need to check the function return for false as when an exception is thrown, the next lines will be skipped and PHP will go to the catch block, or if there is not any catch block it will throw a PHP error. So implementation you suggest is redundant when running in ERRMODE_EXCEPTION.
So yes, the doc doesn't said that x function throw an exception because it will be totally redundant. The error handling page explain everything you need to know.
If you're still not convinced, I suggest to try it by yourself: play with ATTR_ERRMODE and some various PDO functions, and see by yourself.

Is it possible to make PHP exceptions non-fatal?

I wrote a class whose methods frequently throw a number of Exceptions--for example, a NoResultException if the given user ID doesn't correspond to a user, a BadTokenException if the token was wrong, an EmailTakenException if the e-mail address is already registered, etc.
I am trying to write a test program using it really quick. I was feeling lazy and I didn't want to write try/catch blocks. I probably will now, but I still have to ask: is it possible to change PHP's behavior and make it so that Exceptions don't produce fatal errors? In other words, can I make my script catch the Exceptions and output them using the default exception handler (since I'm using XDebug and the backtrace is nice), but allow the script to finish executing? Then I can just see the message of the error (like "The e-mail address is already taken") without stopping the rest of the page from being printed.
Thanks.
use trigger_error instead. it throws non-fatal errors
trigger_error("Custom Error", E_USER_ERROR);
display it via set_error_handler()
see
http://us1.php.net/trigger_error
and
http://us1.php.net/set_error_handler
You can only make exceptions non-fatal if you catch them through try/catch blocks and you've just said that you're too lazy to do that? This makes no sense. You either use trigger_error or you add try/catch blocks.
You can have uncaught exceptions be non-fatal by creating an set_exception_handler function to handle them. Most of the time I just show a HTTP 500 system error page. If there is a way to recover (Which I'm not sure why you wouldn't do it in a try/catch) you can do there by looking at the Exception class and the error code number in the exception.

Categories