how to handle exceptions/errors in php? - php

when using 3rd part libraries they tend to throw exceptions to the browser and hence kill the script.
eg. if im using doctrine and insert a duplicate record to the database it will throw an exception.
i wonder, what is best practice for handling these exceptions.
should i always do a try...catch?
but doesn't that mean that i will have try...catch all over the script and for every single function/class i use? Or is it just for debugging?
i don't quite get the picture.
Cause if a record already exists in a database, i want to tell the user "Record already exists".
And if i code a library or a function, should i always use "throw new Expcetion($message, $code)" when i want to create an error?
Please shed a light on how one should create/handle exceptions/errors.
Thanks

The only way to catch these exceptions is to use a try catch block. Or if you don't want the exception to occur in the first place you need to do your due diligence and check if the record already exists before you try to insert the record.
If it feels like you're using this all over the place then maybe you need to create a method that takes care of this for you (Dont Repeat Yourself).

I don't know Doctrine, but regarding your concrete usage, maybe there is a way to determine if you are facing a duplicate entry, something like :
try {
/* Doctrine code here */
} catch (DuplicateEntryException $e) {
/* The record already exists */
} catch (Exception $e) {
/* Unexpected error handling */
}
Or maybe you have to check if the Exception code equals 1062, which is the MySQL error code for duplicate entries.
Any code that may throw an exception should be in a try/catch block. It is difficult in PHP because you cannot know which method throws an Exception.
You should also have a big try/catch block in your main PHP file that avoids displaying the stack trace to the user, and that logs the cause. Maybe you can use set_exception_handler for this.

Related

Writing functions that deal with exceptions

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).

When is error checking too much?

During the process of my PHP learning I have been trying to read up on the best practices for error reporting and handling, but statements vary person to person and I have struggled to come up with a clear concise way of handling errors in my applications. I use exceptions on things that could go wrong, but for the most part it is hard for me to understand whether an exception should kill the application and display an error page or just be caught and silently dealt with.
Something that seems to elude me is, is there such thing as too much reporting? Every single time you call a function something could go horribly wrong meaning that if you were to confirm every single function call you would have to fill pages with if statements and work out what effect one failure may have on the rest. Is there a concise document or idea for error reporting that could clear this up for me? Are there best practices? What are the best examples of good error handling?
Currently I do the following:
Add important event results to an array to be logged and emailed to me if a fatal error was to occur
Display abstract/generic errors for fatal errors.
Use exceptions for cases that are likely to fail
Turn on error reporting in a development environment and off for live environment
Validate all user input data
Sanitizing invalid user input
Display concise, informative error messages to users without providing a platform for exploitation.
Exceptions are the only thing that you haven't understood IMHO: exceptions are meant to be out of your control, are meant to be caught be dealt with from outside the scope they are thrown in. The try block has a specific limit: it should contain related actions. For example take a database try catch block:
$array = array();
try {
// connect throws exception on fail
// query throws exception on fail
// fetch results into $array
} catch (...) {
$array[0]['default'] = 'me';
$array[0]['default2'] = ...;
...
}
as you can see I put every database related function inside the try block. If the connection fails the query and the fetching is not performed because they would have no sense without a connection. If the querying fails the fetching is skipped because there would be no sense in fetching no results. And if anything goes wrong, I have an empty $array to deal with: so I can, for example, populate it with default data.
Using exceptions like:
$array = array();
try {
if (!file_exists('file.php')) throw new Exception('file does not exists');
include('file.php');
} catch (Exception $e) {
trigger_error($e->getMessage());
}
makes no sense. It just a longer version of:
if (!file_exists('file.php')) trigger_error('file does not exists');
include('file.php');

Exception re-throwing through layers and usage of status codes

I searched for this for a long time (here too), have read many php codes, but still couldn't find a satisfying answer. It may seem a too wide topic, but it really sticks together - at last for me. Could you please help?
In a php website I have PDO as DAL, what is used by BLL objects, and they are called from the UI. Now if something happens, PDO throws a PDOException. Of course the UI layer doesn't have to know anything about PDOExceptions, so the BLL object catches it. But now what?
I have read that
exceptions are for truly exceptional situations and
one re-throws exceptions from lower layers in order not to get low-level exceptions in upper layers.
Let me illustrate my problem (please don't pay attention to the function args):
class User
{
function signUp()
{
try
{
//executes a PDO query
//returns a code/flag/string hinting the status of the sign up:
//success, username taken, etc.
}
catch (PDOException $e)
{
//take the appropriate measure, e.g. a rollback
//DataAccessException gets all the information (e.g. message, stack
//trace) of PDOException, and maybe adds some other information too
//if not, it is like a "conversion" from PDOException to DAE
throw new DataAccessException();
}
}
}
//and in an upper layer
$user = new User();
try
{
$status = $user->signUp();
//display a message regarding the outcome of the operation
//if it was technically successful
}
catch (DataAccessException $e)
{
//a technical problem occurred
//log it, and display a friendly error message
//no other exception is thrown
}
Is this a right solution?
When re-throwing the PDOException I don't think it would be appropriate to use exception chaining (as this would only make debugging information redundant; DataAccessException gets everything, including the full stack trace from PDOException).
Thanks in advance.
As I understood your post a good resource is this:
Api design
I think that you've done your homework (if I can use the phrase) but you forgot the reason why this thing is being done. In your example I'd create something like
SignUpException
which would inform the upper layers that something has gone wrong about signup. What you do here is essentially masking a database exception with a different named one, which is essentially the same thing, something that although programmatically correct, misses the point of the why-s of doing it in the first place.

What is the advantage of using try {} catch {} versus if {} else {}

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.

Exceptions: Is this a good practice?

This is written in PHP, but it's really language agnostic.
try
{
try
{
$issue = new DM_Issue($core->db->escape_string($_GET['issue']));
}
catch(DM_Exception $e)
{
throw new Error_Page($tpl, ERR_NOT_FOUND, $e->getMessage());
}
}
catch(Error_Page $e)
{
die($e);
}
Is nested try, catch blocks a good practice to follow? It seems a little bulky just for an error page - however my Issue Datamanager throws an Exception if an error occurs and I consider that to be a good way of error detecting.
The Error_Page exception is simply an error page compiler.
I might just be pedantic, but do you think this is a good way to report errors and if so can you suggest a better way to write this?
Thanks
You're using Exceptions for page logic, and I personally think that's not a good thing. Exceptions should be used to signal when bad or unexpected things happen, not to control the output of an error page. If you want to generate an error page based on Exceptions, consider using set_exception_handler. Any uncaught exceptions are run through whatever callback method you specify. Keep in mind that this doesn't stop the "fatalness" of an Exception. After an exception is passed through your callback, execution will stop like normal after any uncaught exception.
I think you'd be better off not nesting. If you expect multiple exception types, have multiple catches.
try{
Something();
}
catch( SpecificException se )
{blah();}
catch( AnotherException ae )
{blah();}
The ideal is for exceptions to be caught at the level which can handle them. Not before (waste of time), and not after (you lose context).
So, if $tpl and ERR_NOT_FOUND are information which is only "known" close to the new DM_Issue call, for example because there are other places where you create a DM_Issue and would want ERR_SOMETHING_ELSE, or because the value of $tpl varies, then you're catching the first exception at the right place.
How to get from that place to dying is another question. An alternative would be to die right there. But if you do that then there's no opportunity for intervening code to do anything (such as clearing something up in some way or modifying the error page) after the error but before exit. It's also good to have explicit control flow. So I think you're good.
I'm assuming that your example isn't a complete application - if it is then it's probably needlessly verbose, and you could just die in the DM_Exception catch clause. But for a real app I approve of the principle of not just dying in the middle of nowhere.
Depending on your needs this could be fine, but I am generally pretty hesitant to catch an exception, wrap the message in a new exception, and rethrow it because you loose the stack trace (and potentially other) information from the original exception in the wrapping exception. If you're sure that you don't need that information when examining the wrapping exception then it's probably alright.
I'm not sure about PHP but in e.g. C# you can have more then one catch-Block so there is no need for nested try/catch-combinations.
Generally I believe that errorhandling with try/catch/finally is always common-sense, also for showing "only" a error-page. It's a clean way to handle errors and avoid strange behavior on crashing.
I wouldn't throw an exception on issue not found - it's a valid state of an application, and you don't need a stack trace just to display a 404.
What you need to catch is unexpected failures, like sql errors - that's when exception handling comes in handy. I would change your code to look more like this:
try {
$issue = DM_Issue::fetch($core->db->escape_string($_GET['issue']));
}
catch (SQLException $e) {
log_error('SQL Error: DM_Issue::fetch()', $e->get_message());
}
catch (Exception $e) {
log_error('Exception: DM_Issue::fetch()', $e->get_message());
}
if(!$issue) {
display_error_page($tpl, ERR_NOT_FOUND);
}
else
{
// ... do stuff with $issue object.
}
Exceptions should be used only if there is a potentially site-breaking event - such as a database query not executing properly or something is misconfigured. A good example is that a cache or log directory is not writable by the Apache process.
The idea here is that exceptions are for you, the developer, to halt code that can break the entire site so you can fix them before deployment. They are also sanity checks to make sure that if the environment changes (i.e. somebody alters the permissions of the cache folder or change the database scheme) the site is halted before it can damage anything.
So, no; nested catch handlers are not a good idea. In my pages, my index.php file wraps its code in a try...cache block - and if something bad happens it checks to see if its in production or not; and either emails me and display a generic error page, or shows the error right on the screen.
Remember: PHP is not C#. C# is (with the exception (hehe, no pun intended :p) of ASP.net) for applications that contain state - whereas PHP is a stateless scripting language.

Categories