daGrevis
daGrevis

Reputation: 21333

Exceptions in PHP. How to use them? How to extend 'em?

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! =]

Upvotes: 1

Views: 335

Answers (3)

ircmaxell
ircmaxell

Reputation: 165201

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:

  1. Change the thrown exception to InvalidArgumentException since it has more semantic meaning (I almost never throw a raw exception).

  2. 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?

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

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

Upvotes: 2

Mark Baker
Mark Baker

Reputation: 212422

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.

Upvotes: 0

Mchl
Mchl

Reputation: 62395

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.

Upvotes: 2

Related Questions