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.
Related
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( ) ; }
Building upon a question I already asked regarding exceptions, I fear that I might be writing php functions wrong then, or abusing the use of exceptions. The reason I say this, is because if custom exceptions are to be caught using try/catch blocks then the following function:
public function get_specific_page($page) {
if (!is_array( $this->_page )){
throw new AisisCore_Template_TemplateException( "<div class='error'>Trying to get a property from a non array.</div>" );
}
return $this->_page[$page];
}
Would then be called such as:
try{
get_specific_page($page);
}
catch(Exception $e){
echo $e->getMessage();
}
The problem with this approach is that I have many functions that are written like this, either checking to see if a file exists, throwing an error. Checking to see if a value is set in an array, throwing an error and my issue is that the file which deals with these function calls may become over loaded with try catch.....
So my question is, how would I better write functions like this so that I don't have php files over loaded with try catch statements, yet still be able to have y own custom functions.
Is it as obvious as writing the try catch inside the function it's self?
The reason I ask, if because I am use to working with fameworks and in companies where we write our functions as you see above. How ver I have worked with code bases that have tons of these functions and I dont see half the files that are useing them doing a bunch of try catches...
Update:
I was looking through zend source to better understand exceptions and came across this:
public function setMessage($messageString, $messageKey = null)
{
if ($messageKey === null) {
$keys = array_keys($this->_messageTemplates);
foreach($keys as $key) {
$this->setMessage($messageString, $key);
}
return $this;
}
if (!isset($this->_messageTemplates[$messageKey])) {
require_once 'Zend/Validate/Exception.php';
throw new Zend_Validate_Exception("No message template exists for key '$messageKey'");
}
$this->_messageTemplates[$messageKey] = $messageString;
return $this;
}
You can see how they throw a new exception message near the bottom, this function is not called by doing:
try{}catch(){}
yet when it throws an exception, there is no issue with "uncaught exception with message"
In my opinion, your approach is correct in general. However, a few notes:
You should refrain from using HTML formatting in exception messages. Generally, you don't know how the exception that you throw will be handled. For example, an exception handler could just write the message to a log file (you don't want HTML formatting then), present it to the user in a special error view (in which case the view itself should contain the HTML formatting), or simply ignore it (no need for formatting then, anyway).
Catch only exceptions that you can handle. If you know that your function throws an AisisCore_Template_TemplateException, you should just catch that exception and let all other exceptions bubble up to an exception handler that can handle them. You can use set_exception_handler to define such an exception handler that catches all uncaught exceptions by default (this is probably the case in your example from Zend Framework). Plainly put: Only catch exceptions in places where you know how to handle them.
Only use exceptions as what the name implies: to handle (unexpected) exceptions in your control flow. Using exceptions to control the regular flow of your program is possible, but generally considered bad design (just as a side note, your code samples look alright).
For the sake of completeness, some alternatives to using exceptions:
Use return codes instead of exceptions. This is old-school C-style. The advantage is that you don't need to wrap statements with try/catch-statements. However, you have to check the return values of each procedure, which is easy to forget. When using exceptions on the other hand, you reduce the risk of unexpected errors, since uncaught exceptions produce a fatal error per default.
Use PHP errors. See the trigger_error function for this. Custom errors are however nearly impossible to catch in PHP (except by using set_error_handler, which only works at global level).
Few days ago I deal with errors like this...
exit( 'Error!' );
or exit( 'Error!' );
Doh, right? =] Now I'm trying to learn Exceptions. This is how far I got...
http://pastie.org/1555970
Is that correct use of them? It would be cool that I can have more info about 'em. Like file where exception is thrown and line of that file. I know that there are build-in methods (in Exception class), but I want to somehow extend it so I don't need to write...
throw new My_Exception( '...' );
catch( My_Exception $e ) {
echo $e->my_method();
}
...but use old syntax.
throw new Exception( '...' );
catch( Exception $e ) {
echo $e->getMessage();
}
...or maybe you have any greater thought of Exceptions? How to deal with them? Help me! =]
In general you only need to echo/log exceptions, that cannot be otherwise handled. This pretty much means, that if you put your entire application within try block, there's only one place where you need to put echoing/logging logic (i.e. the catch block associated with the outermost try block).
If on the other hand the exception can be handled without stopping the application (in your example this could be providing a default numeric value, instead of incorrect value), then there's usually no need to echo/log it.
If you do want to log such exceptions (for debugging for example), then your application should contain a logging framework, so that it's enough to do in your catch blocks something like
} catch (Exception $e) {
ExceptionLogger::log($e); //static method == ugly, but it's for simplicity in this example
// do whatever needs to be done
}
log() method above would check if the logging is enabled, and if it is savenecessary data to a file.
Exceptions should be typed based upon the error that you find. The Spl Exceptions are a good start, but you really should be creating your own exceptions as well. Some common ones that I use:
FileNotFoundException extends RuntimeException <- self explanatory
HTTPException extends RuntimeException <- Used for http classes when a non-200 result is encountered
DatabaseQueryException extends LogicException <- Used for database query errors
Now, by typing them specifically, it lets you handle the errors in your code. So let's say that you want to fetch a HTTP resource. If that fails with anything but a 404, you want to try a backup URL. You could do that with:
try {
return getHttp($url1):
} catch (HttpException $e) {
if ($e->getCode() != 404) {
try {
return getHttp($url2);
} catch (HttpException $e2) {
//It's ok to ignore this, since why know it's an HTTP error and not something worse
return false;
}
} else {
return false;
}
}
As far as your example code that you posted, I would change a few things:
Change the thrown exception to InvalidArgumentException since it has more semantic meaning (I almost never throw a raw exception).
You should try to avoid catch(Exception $e) at all costs. You have no idea what exception was thrown, so how can you possibly handle it?
Only catch exceptions that you are reasonably sure you know how to handle (and outputting an error/logging is not handling, it's removing the usefulness of the exception). You should never see something like catch($e) { logerror($e); } or catch($e) { print $e->getMessage(); } since netiher is actually handling the exception.
If you don't fix or workaround the cause of the exception in your catch block, you should re-throw it. Let the code above you in the stack try to handle it. This is especially true with libraries and classes that are reused all over the place.
Now, with user interfaces, it may be acceptable to catch the exception and show the user an error message. So your example where you print the exception's message might be ok, but you'd really need to think about the use-cases of it. Are you calling it from a model or controller? If so, it may be ok display an error message. Are you calling it from a library? If so, it's probably better to let the exception bubble up.
Also, don't use a global try{} catch() {} block. Instead, install an Exception Handler to handle it for you. It's cleaner, and more semantically correct (since any try{}catch{} implies that you know how to handle the exception that you caught, whereas the exception handler is precisely meant for exceptions that weren't handled because you didn't know how to handle them.
Exceptions are for exceptional circumstances. Do not use them for all error conditions. If a user submits a password that's too short, don't throw an exception, handle that in validation. But if your hash function is expecting sha256 to be available and it isn't, that's a time for an exception. Exceptions are useful for program errors (when a condition that is unexpected happens, such as invalid input to a function), state errors (when the application enters a state that is unknown or unstable, such as if the requested view does not exist) and runtime errors (when the application encounters an error that can only be detected at runtime, such as a file-not-found error).
There is an entire page of the PHP manual devoted to extending exceptions and that page also gives you a lot of information on the methods to identify file/line number, backtrace etc. where the exception was thrown. This is the type of information that is extremely useful for debugging.
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.
I am switching from plain mysql in php to PDO and I have noticed that the common way to test for errors is using a try / catch combination instead of if / else combinations.
What is the advantage of that method, can I use one try / catch block instead of several nested if / else blocks to handle all errors for the different steps (connect, prepare, execute, etc.)?
I'd use the try/catch block when the normal path through the code should proceed without error unless there are truly some exceptional conditions -- like the server being down, your credentials being expired or incorrect. I wouldn't necessarily use it to handle non-exceptional errors -- say like the current user not being in the correct role. That is, when you can reasonably expect and handle an error that is not an exceptional condition, I think you should do your checks.
In the case that you've described -- setting up and performing a query, a try/catch block is an excellent way to handle it as you normally expect the query to succeed. On the other hand, you'll probably want to check that the contents of result are what you expect with control flow logic rather than just attempting to use data that may not be valid for your purpose.
One thing that you want to look out for is sloppy use of try/catch. Try/catch shouldn't be used to protect yourself from bad programming -- the "I don't know what will happen if I do this so I'm going to wrap it in a try/catch and hope for the best" kind of programming. Typically you'll want to restrict the kinds of exceptions you catch to those that are not related to the code itself (server down, bad credentials, etc.) so that you can find and fix errors that are code related (null pointers, etc.).
In general, try-catch blocks are great because they will break (move to the catch statement) whenever the exception occurs. If-else blocks rely on you predicting when the error will happen.
Edit:
Also, catch blocks won't stop your code from halting when an error is hit.
Throwing and catching an exception is an expensive operation compared with most any other primitive operation. If this is a piece of code that needs to perform well (eg, in a tight loop), you will want to look at your use case - if you expect the exceptions to be thrown relatively often, you will be better off with an if/else perforance-wise (unless the underlying code is just wrapping an exception for you, in which case there's no gain at all). If the exceptions are only thrown in rare circumstances, then you're better off with a try/catch to avoid the overhead of branching in a tight loop.
The advantage of try/catch, and exceptions in general, is more for the people developing libraries like PDO. They allow a system developer to handle undefined situations or unexpected results in a quick and easy way. Take a database connection. What should a system do if the database can't be reached. Should it halt execution? Try again? Throw a warning and continue? The system developer can't know what you'll need it to do, they they throw an exception, which you'll later catch and handle.
The advantage for you, as a consumer of the system is rather than getting some vague error code back, or a simple boolean false that it failed, you get an Exception object which will
Be named in such a way that it's more obvious what went wrong (If I remember right, PDO only has one Exception type, but other systems contain multiple exception types for different kinds of errors)
May/should contain methods and properties which can help you figure out why the exception was thrown
That's the theory anyway. There are lots of smart people who claim Exceptions are the way to go. There are also lots of smart people who think Exceptions are the devil, and a crutch for lazy system developers. There is nothing resembling consensus on this issue.
#Perchik:
My general philosophy of error handling:
You should use if / else to handle all cases you expect. You should not use try {} catch {} to handle everything (in most cases) because a useful Exception could be raised and you can learn about the presence of a bug from it. You should use try {} catch {} in situations where you suspect something can/will go wrong and you don't want it to bring down the whole system, like network timeout/file system access problems, files doesn't exist, etc.
Vexing exceptions
Try/Catch totally separates the error handling logic from the object business logic.
That’s exactly the advantage, using one try/catch instead of multiple if statements. You will also be able to catch any unanticipated errors.
Everybody else had good answers - but I figured I would throw my own in:
Try/Catch is an actual exception handling mechanism - so if you change your exceptions, it will automatically work on all try/catch statements.
Try/Catch gives the opportunity to run code even in the case of a major exception that might kill the if/else and in addition, the try statement can be rolled back (if you're savvy).
Since PDO is using objects, they are raising Exceptions if an error occur. The old mysql/mysqli were mere functions and didn't throw Exceptions they simply returned error codes. Try/catch is used when an Exception can be thrown from the code, and you catch it in the catch-clause, which is an object oriented way to handle errors. You can't catch Exceptions with if/else blocks - they share nothing with try/catch.
In php by using Try Catch with inheritence, We can throw exception from another class.
Example :- I am in the controller and validating user data by using Models.
If any error triggers, I just have to throw exception from Model methods.
The execution in try will break and catched in the Catch Block.
So There is less overhead of returning bool vales and checking that.
Apart from this Try Catch works great When using in chain ( Try - Catch inside another Try - Catch ).
This question has been asked more than a decade ago out of the wrong premise. In reality if and try are incomparable matters. Sadly, but up to this day people catastrophically confuse exceptions with try catch, thinking one is inseparable from another.
In the way it is asked, indeed it makes very little sense to change if {} to try {} in the meaning of obligatory try wrapping a single line of code to test for the error.
However the actual question is What is the advantage of using exceptions versus if {} else {}.
And it starts to make a whole world of sense immediately: exceptions allow automated error reporting, when neither try catch nor if else is ever have to be written.
An exception is essentially an automated way to write if ($result == FALSE) raise_error(); Without exceptions you are bound to test every operation's result manually. It would be just stupid to recreate the same behavior using exceptions. In most cases a thrown exception should be left alone, unless there is a certain handling scenario. In all other cases it has to bubble up elsewhere, hence no try {} catch {} has to be written.
Let's say we are writing an a/b division code and the most famous exception case has occurred i.e. 0 divide error, what do you think can be done next?
1. You can print a message and exit.
2. You can print a message and let the user re-enter the values, etc.
There are cases when different people/vendors want to handle the same exception case in different way. The catch block let them do this with ease. If you need to change the way how a certain exception case will be handled, you just need to change the catch block.
TRY/ CATCH can be used within the programming context where you have very little information about the error or you think that might can occur such as.
#include <iostream>
using namespace std;
int main (){
try{
while(true){
new int[100000];
}
}
catch(bad_alloc& e){
cout << e.what() << endl;
}
}
Although there are no semantic or compile-time errors in the program, but it's understandable that it posses a run-time error which is "bad_alloc" which appears when you try to continuously allocate the memory and your program run out of memory. This exception is defined in bad_alloc standard class which is a child-class of class "Exception", since it throws an implicit exception, throw keyword is not implied here.
You can also use try/catch to check if the file is accidentally deleted and can use if/else to check if there exists a file or not, both have their own advantages.
Try and Catch functions are useful whenever there is a communication between functions. In Try and Catch , if there exists an exception in the TRY block, the control is transferred directly to the CATCH block which would store our exception condition. This however is not possible in case of IF ELSE, where in IF condition , if there exists an exception, the control cannot go to the ELSE block howsoever in any case.
int division(int a,int b){
if(b==0)
throw 101;
return a/b;
}
int main()
{
int a=10,b=0,c;
try{
c=division(a,b);
cout<<c<<endl;
}
catch(int a){
cout<<"Division not possible by 0"<<endl;
}
}
Consider the following Code: throw and catch function is used for communication between functions division and the main function.
Note that the statement to print c is not executed when b is 0 as the control directly transfers to the catch block after the value os thrown.
This however would not have been possible , had it been IF ELSE here.