# Thread: why throw an exception?

1. ## why throw an exception?

I suppose this is a mode of thinking question more so than PHP code.. but i have been wondering WHY throw an exception?

I mean since you have to wrap the whole thing in "try" "catch" and then an "if"(or other statement) to define the err and throw the exception.. and it's not like it's thrown / and caught automatically when an err occurs. Why not just use a "if" statement by itself?

I am VERY new at PHP, so my CLASSES and METHODS are still simplistic,maybe this is why I am asking this question, but for the life of me I cannot see a PRACTICAL use to Exceptions.

2. It basically moves the "IF" logic from your code into the class.
Exceptions are supposed to be things that are not supposed to have to be handled by your class.

Ex:
Say you have a class that loads up some user data from the database, and needs an active db connection.
You would throw an exception if the connection passed to that class is not active, since the class should not care about handling connections.

3. Even without the classes, it moves the error handling logic to the area of the program that knows how to deal with it.

You can have a function that just does whatever it is supposed to do, and if there's an error it throws an exception. The section of code that called the function can then figure out how to deal with the error. In some places an error can be okay and the section of code can continue on, in others it'll log the error and display an error message before aborting.

You used to see things like returning boolean false for an error, but that gets confusing with other functions that should return boolean false as a normal part of execution.

4. Yes, I always was told that try throw catch changes the way errors are handled. Instead of crashing w/ some errors it will throw the error or something that is designed to deal with it.

5. I never really understood the point either until I watched some of the Zend Framework webinars (I'm an OOP beginner as well).

It makes error handling much more specific for you and with a lot more control. For instance, if you have a method that accepts a date in a certain format, you can throw an Exception for any input that is not acceptable. Then, you can use the Exception to do whatever it is you want to do (like send the user to an error page). It also makes it great for debugging because you can have the Exception display whatever kind of message you want to let you know what's wrong and where.

That's my understanding of it so far. I'm sure there's a lot more to it, so I hope I didn't botch that too badly.

6. My take on it!

It's useful because:
• You can know what the specific error is (and in a standard way). Without exceptions, you would have to start returning things like '-1', 'false' or 'null' if an error occurred. Okay, great. But what if there were many types of errors that could occur and you want to know which specific one it was? Without exceptions, you would have to store the error in some variable somewhere (like $this->error = 'error_102'). That's ugly and non-standard. • Exceptions bubble up. Say you have class to connect to an HTTP server and it uses another class for sockets. What if an error occurs with the sockets class rather than the HTTP class? Without exceptions, the HTTP class would have to detect the error and then re-package for you, by setting$this->error = 'socket_error' or something. It's much easier if the socket class can just raise an exception that will 'bubble up' until something cares to catch it. The HTTP class is just responsible for handling HTTP. It's not supposed to handle errors regarding the socket.
• You can handle groups of errors together. Exception objects can inherit from other exception objects.

Note: The 2nd bullet point is a pipe dream in PHP. Most PHP functions and classes do not throw exceptions yet, so there's no standard SocketException or anything, so a HTTP class (as of right now), would have to re-package the socket error.

___

For an example:

I have this (unfinished) set of classes to query information from TeamSpeak 2 servers (voice chat servers). The following code merely sends a simple command to the server:
http://github.com/sk89q/teamspeak2qu...Query.php#L379

But think of the many things that could go wrong! While writing or reading from the socket, it might just time out. The server might return an error. Or worse, the server might even return some intelligible response. What if you haven't even connected to the server yet?

But does superLogin() need to care about that? No. All it needs to do is send that one command. (Ignorance is bliss!)

It does call query() though:
http://github.com/sk89q/teamspeak2qu...Query.php#L203
query() does the heavy lifting of sending the command and reading the response. Look at the exceptions it throws:
• TS2SocketUnconnectedException: Not even connected yet, smart one...
• TS2SocketTimeoutException: Socket timed out
• TS2ErrorException: The server gave me an error message =(
• TS2ProtocolException: I don't even know what the server is saying

These exceptions would just "bubble up" past superLogin() and to the code that called superLogin(). There the error can be handled, or, if that code doesn't care either, it can bubble further and further up (until PHP catches it).

Best yet, look at the tree of inheritence:
http://code.therisenrealm.com/projec...exception.html

If the calling code doesn't care what the error even is, only whether there was an error, it can just handle 'TS2Exception'.

7. I am trying to get what people are saying. I would saw I am at Crowden's level. Except, the way my brain is working ...it's seeing it like this ( assume all variables are predeclared, am concerned only with the reasoning not the syntax) :

------------------------------------------------------------------------------------------------------------------------------------------------------------

function X($a,$b){
try {
if ($b==0) { throw new Exception ("That's a singularity! You cant divide by 0."); } } catch(Exception$e){
echo"WARNING!!<br>";
$c=$e->getMessage();
return $c; }$c=$a/$b;
return $c; } ------------------------------------------------------------------------------------------------------------------------------------------------------------ the TRY statement doesnt actually LOOK or WAIT for ran error... right? what I mean is , if I didn't put "$c=$a/$b;" AFTER the TRY then the error would not be caught on time.. so I dont see the gain in this. Also, I needed the IF to THROW the exception... once the error case was found, which case why bother why not just do something like this:

------------------------------------------------------------------------------------------------------------------------------------------------------------

function X($a,$b){

if ($b==0) {$e= ("That's a singularity! You cant divide by 0.", 10);
echo"WARNING!!<br>";
return $e;// I think you could even use a header stament to send the user to an error page AND the programmer would know that the "singularity" error came from here. }$c=$a/$b;
return $c; } ------------------------------------------------------------------------------------------------------------------------------------------------------------ I know the case is sooooo rudimentary, but you can see why the second example seems more to the point. Maybe I am just entirely off base in my very novice OOP thinking. 8. Well I must be wrong. I thought Exceptions were meant to handle "unforeseen catastrophic errors". Passing 0 to your function X() is a foreseeable user error which could have been trapped higher up in the programme and dealt with properly there. If that was the case then all the exception in the class is doing is providing some insurance, except now you have to do a try{}catch somewhere else. 9. Originally Posted by Cups Passing 0 to your function X() is a foreseeable user error which could have been trapped higher up in the programme and dealt with properly there. What if you're not the author of the higher up parts? You're developing a library for other people to use an API your website is exposing, and it's likely those users won't fully understand your library and might pass your functions bad input. 10. @Cups: You don't need to add a try-catch for such a case. If you're not expecting an exception, don't try to catch one. If one *does* manage to happen, logging code can just log it and the user can be presented an error message, but that really shouldn't happen. @dresden_phoenix: Exceptions are supposed to be used like this: PHP Code:  <?phpfunction X($a, $b){ if ($b == 0) {        throw new Exception ("That's a singularity! You cant divide by 0.");    }        $c =$a / $b; return$c;}try {    $result = X(4, 0);// The exception "bubbled" up} catch (Exception$e) {    echo "WARNING!!<br>{$e->getMessage()}";}  The equivalent non-exception way that you suggest would be like this: PHP Code:  <?phpfunction X($a, $b){ if ($b == 0) {        return array("That's a singularity! You cant divide by 0.", 10);    }        $c =$a / $b; return$c;}$result = X(4, 0);if (is_array($result)) {    echo "WARNING!!<br>{$result[0]}";}  That's non-standard and ugly. Worse, what about in a case like this: PHP Code:  <?phpfunction Y($l, $b){ if ($b == 0) {        return array("That's a singularity! You cant divide by 0.", 10);    }        $new = array(); for ($i = 0; $i < count($l); $i++)$new[$i] =$l[$i] /$b;    }    return $new;}$result = Y(array(4, 5, 2), 0);// How do you detect the error?// 

11. @dresden_phoenix, just a little rule of thumb I took from using try/catch and exceptions. There is no error checking or sanity checking within an try block. There is no throwing errors or exceptions from directly inside the try block.

Throwing exceptions and doing any form of error checking or sanity checking should happen within the functions or methods that are being called within the try block.

One example I can think of, off the top of my head, is a database. Normally you would be running a whole lot of checking to make sure the code finished without error, usually with a sea of IF statements.

PHP Code:
 try {    $db = new Database::getConnection( 'mysql', 'logic', 'superpass' );$db->selectDefaultDatabase( 'example_test' );    $db->setConnectionCharset( 'utf-8' );$db->query( 'SELECT id, name, date FROM example_users LIMIT 5' );    $rows =$db->fetchAll();        // ... do stuff with rows ...        } catch ( DatabaseException $e ) { // If any error occures it will stop the above code and come down here. // Leaving the above code clear of any messy error checking. var_dump($e ); # For debugging.    exit;}  

12. It allows easy error handling between development and live code.

On my development server I use set_exception_handler() to print a backtrace and the error to the page. On the live server I print a friendly error message to the user and log the error in the database with as much debugging information as possible.

13. Originally Posted by sk98g
@Cups: You don't need to add a try-catch for such a case. If you're not expecting an exception, don't try to catch one. If one *does* manage to happen, logging code can just log it and the user can be presented an error message, but that really shouldn't happen.
That makes sense.

Ok, so in the simple example given maybe dividing by zero is not a 'catastrophic unforseen error', but it does represent predictable, but possible user error, which you would try and snag elsewhere.

I realise this depends on how much smartness, or responsibility a particular object is endowed with.

But to get that message back to the user would you use the Exception? that would seem to couple the class to much to a single implementation.

I am tending to making sure if the object is not that smart (ie it trusts what it is given) then I stipulate as much in the docblock comments, but I think you are saying in the example above - if the incorrect arg 0 is passed, then throw the Exception.

I suppose I am asking myself about the differentiation between getting messages back to the user and the whole question of usability, and giving myself helpful debugging information (perhaps that could be described better as "getting the message back to the programmer"), and the difference between them is blurred in my mind.

14. If you're the same person writing the library code and the code that uses the library, exceptions do seem like a waste of time. It's true in that case. However, if you're going to write re-usable code, other people who might use your library might make an error and not know it. If your library is complex, bad input might cause it to enter an undefined state and error at some point later in the library. At that point, it will be very annoying to debug because the calling code can call 50 methods after the bad call before an error is noticeable. Now which call in those last 50 caused the problem? If you wrote the library, it's an easy answer because you know the library like the back of your hand. However, if you're someone who just got a copy of it, then you better get a cup of coffee.

Example: A library that access a web service might return some data in CSV format. Let's say the calling code parses this CSV data and re-formats it. That's three parts to the code: web service client, CSV parser, and the formatter. One day the web service returns tab delimited data. When you view the page with the output, it's completely wrong. Where did it go so wrong? The web service client? The CSV parser? The formatter? If the web service client threw an error when it received the bad data, you would know exactly where the problem was. Otherwise you would have to ask yourself: "did the formatter screw up somewhere?" or "did the parser choke on some data?"
(That wasn't a very complicated example, but the point is there.)

15. Thanks, you make the same point Dan did, but with an example. Most kind of you both.

The fact is even if I wrote the lib and am the only person to use it, there is no way I can keep all this in my head, so yes clearly, I need to use Exceptions more.

I had understood that Exceptions always needed a try{}catch block to be invoked.

So let me get that out of the way now, and try and nail this.

I liked TomB's comment about dev/live, as it makes me think of Exceptions in terms of how I currently use error levels and display_errors() - something I set per script or using an include file.

Here is my workup of the example by sk89g, taking on board Dan's and TomB's comments - I hope.

1. set up the exception handler
//exception_handler.php
PHP Code:
 <?php/* *   Nail the simplest use of exceptions - include this ...  */// change the way the message is handled$DBG = 0 ; // public messages are handled$DBG = 1 ; // Pro messages appearfunction ProHandler($e) { echo "Uncaught exception: " ,$e->getTraceAsString() , $e->getMessage() , PHP_EOL ; // show stuff you wouldnt want the public to see}function PublicHandler($e) { echo "Now, you see there was no need for that behaviour at all. The very fact you can see this is a cause of embarrassment, but itsnecessary."; // now do silent logging}if( $DBG ){set_exception_handler('ProHandler');}else{set_exception_handler('PublicHandler');}?>  2. In the set of classes, which do not care about what happens to the exceptions, all they know is "feed me what I want or I yell". Their messages are sent to Pro's using the code, but whether they are displayed or not is decided elsewhere, they can only describe the effect that external is having on them. exceptions.php PHP Code:  <?phpinclude( "exception_handler.php") ;class WebService { public$data = "1 2   5   4   3";  // bad data    //public $data = "1,2,5,4,3"; // good data function getData() { return$this->data ;    }}// takes csv data from a webservice and re-orders itclass CSVparser{    public $orderedData = array(); function __construct( WebService$ws ){    $ord = explode("," ,$ws->getData() );    if( count($ord) <= 1 ) throw new Exception('Given bad or empty data'); sort($ord );    $this->orderedData =$ord ;    return $ord ; }}// given an array, formats it using a tag nameclass Formatter{ function applyFormat($data, $tag = 'b' ){ if( empty($data ) )         throw new Exception('Not given any data');        if( ! in_array($tag, array('b','i','u') ) ) throw new Exception('Not given permitted format'); foreach($data->orderedData as $v ) echo '<' .$tag .'>' . $v . '</' .$tag . '>' ;    }}?> 
// usage

$ws = new WebService ;$csv = new CSVparser( $ws );$bold = new Formatter ;

//$bold->applyFormat($csv , 's' ) ; // bad instruction
$bold->applyFormat($csv , 'b' ) ; // good instruction

Edit:

I found out more about getTraceAsString() so I edited the examples a wee bit, also split them into two files.

So if that is an example of a simple but valid use of Exceptions, then I am both gratified and better informed.

Thanks all.

One thing that did bother me though is if I did not pass a valid $ws object to the CSVparser,$csv = new CSVparser();

I got this expected message;

"Catchable fatal error: Argument 1 passed to CSVparser::__construct() must be an instance of WebService, none given,"

But where/how could I have caught that then?

16. You shouldn't need to be catching that fatal error (and you can't, because it's not an exception) because you're still supposed to use the library correctly. Because you can incorrectly use a library without creating complete havoc does not mean that you should. It's the same situation with X() above. No need to just break things.

By the way, I would personally catch the error with the web service somewhere along the line to present a friendly message ("come back later," etc.), especially if that is not an integral part of the page. An exception will cause the page to stop executing at the point that the exception was thrown, so it will utterly break the entire page. However, if you're going to catch the exception, you should not be throwing Exception and catching Exception, because you might be catching a different error and not know it.

Instead of throwing instances of Exception, I would throw instances of classes that inherit Exception. That way, you can, if you want, catch specific errors.

PHP Code:
 <?phpclass DivideByZeroException extends Exception {}class InvalidCSVDataException extends Exception {}function do_bad_math() {    throw new DivideByZeroException();}function test_error($) { throw new InvalidCSVDataException()}try { do_bad_math(); test_error();} catch (InvalidCSVDataException$e) {    echo "Invalid CSV data!";} 
Just catching "Exception" would be bad because you would hide the DivideByZeroException. Plus, now you can catch specific errors!

BTW, SPL has some standard exceptions:
http://www.php.net/~helly/php/ext/sp...Exception.html

17. As the very last catch block, it is a good idea to catch Exception as a catchall, unless you have a different default defined with set_exception_handler. Otherwise, if the Exception is not one of the ones you are searching for, it will be caught by the generic exception handler, which puts up a nice, cryptic "Uncaught Exception" message.

18. Thanks for your replies, I feel I am learning a lot from this thread.

No need to just break things.
I wasn't being sardonic, I actually wanted to know how to handle the class not being passed a correct class, but lets forget that for now, I am sorry for wandering off the point.

You showed:

PHP Code:
 function test_error($) { throw new InvalidCSVDataException()}  So that would mean that, generally speaking anyway, the information to be passed up, say to the programmer, would need to be written in the same file as the class. Edit: InvalidDataException corrected, now calls __construct() and sets the message property. PHP Code:  class InvalidCSVDataException extends Exception { function __construct(){$this->message = "Something went wrong with the                          CSV data this class was expecting"; }}// takes csv data from a webservice and re-orders itclass CSVparser{    public $orderedData = array(); function __construct( WebService$ws ){    $ord = explode("," ,$ws->getData() );    if( count($ord) <= 1 ) throw new InvalidCSVDataException(); sort($ord );    $this->orderedData =$ord ;    return $ord ; }}  So the benefit of this is that the main class, CSVparser is neater looking, and in TDD terms, I would develop the Exception(s) and the main class at the same time. Am I on the right track? 19. I didn't mean my post in that tone. I was a bit confused about your post though. Are you asking about how to handle it from the point of the library writer or the user of the library? I personally don't put the exceptions in the same file (providing you mean exceptions when you mean "information to be passed up"). I like to follow the conventions of Java and have one class/interface per file because it makes it easier to find the definition for a class. If you share exceptions between different classes, which file would you put the exceptions in to? And yes, you would have to plan the exceptions as you develop. BTW, if you want to override the message for the exception, override the constructor. That's where the message is accepted and stored. Besides that, Exception::getMessage() is marked final and so you can't override it anyway. 20. I agree with sk89q, it is all about having good code structure. It's really in the same vein as good grammar, spelling, and brushing your teeth. 21. Are you asking about how to handle it from the point of the library writer or the user of the library? User of the library, someone running with errors on, i guess they'd see the fatal dead stop and message in any case. What about public users though, is there a way to recover from that fatal error? BTW, if you want to override the message for the exception, override the constructor. Yeah, bad mistake, I will go back and correct the example in the previous post; Should be: PHP Code:  class InvalidCSVDataException extends Exception { function __construct(){$this->message = "Something went wrong with the                          CSV data this class was expecting"; }}  
If you then feed it a non-csv list you get a message similar to this if you have DBG = 1

Code:
Uncaught exception: #0
\var\www\html\xxx\services\exceptions.php(73):
CSVparser->__construct(Object(WebService)) #1 {main}
Something went wrong with the
CSV data this class was expecting
If you share exceptions between different classes, which file would you put the exceptions in to?
I think you are way ahead of me now.

Remember I am still focusing on this example and as such I cannot perceive when such a specific class as this:

PHP Code:
 class InvalidCSVDataException extends Exception {}  
... would benefit from being shared with anything else.

Although I am willing to take your word for it, but I think I will likely try and build on what I have learned so far. I have climbed quite a few rungs up this particular ladder. Thanks.

Edit:

After deliberation I wonder if you are telling me something like this:

If CSVparser, WebService and Formatter are all distinct "classes" in their own files,
then their exceptions would probably be kept in files like:

CSVparserExceptions
WebServiceExceptions
FormatterExceptions

And the library that needs all these components uses something like
autoload to get each of the Exception files.

Or maybe each class just includes() its' Exception files?

22. Originally Posted by Cups
User of the library, someone running with errors on, i guess they'd see the fatal dead stop and message in any case.

What about public users though, is there a way to recover from that fatal error?
Public users?

Originally Posted by Cups
Yeah, bad mistake, I will go back and correct the example in the previous post;

Should be:
PHP Code:
 class InvalidCSVDataException extends Exception { function __construct(){  $this->message = "Something went wrong with the CSV data this class was expecting"; }}  That works, although I prefer this way: PHP Code:  class InvalidCSVDataException extends Exception { function __construct(){ parent::__construct("Something went wrong with the CSV data this class was expecting"); }}  Doesn't really matter though, since$message is protected.

Originally Posted by Cups
I think you are way ahead of me now.

Remember I am still focusing on this example and as such I cannot perceive when such a specific class as this:

PHP Code:
 class InvalidCSVDataException extends Exception {}  
... would benefit from being shared with anything else.
In this example, each library (we have three) consists of only one class. However, if you the library consisted of several classes and you followed the 1-1 class-file relationship, then you might have to share an exception among the different classes (and consequently the different files).

Originally Posted by Cups
After deliberation I wonder if you are telling me something like this:

If CSVparser, WebService and Formatter are all distinct "classes" in their own files,
then their exceptions would probably be kept in files like:

CSVparserExceptions
WebServiceExceptions
FormatterExceptions

And the library that needs all these components uses something like
autoload to get each of the Exception files.

Or maybe each class just includes() its' Exception files?
This question doesn't really have a "right answer" at the moment because we're on the verge of migrating to 5.3 (or at least in the future).

I personally keep each exception to their own file because of that one class to each file rule. That makes autoloading possible, but if you want to use autoloading right now, you would have to put everything into the same directory. I want to stick to the rule and still be organized, and so for the mean time, I don't autoload. Right, I put my class path in include_dir and just use require_once "com/example/...etc.php" (this does make portability a problem though, but Apache servers can change this with a .htaccess).

Thankfully, PHP 5.3 is coming out soon (or eventually, at least) though, and I am highly anticipating that. I have already organized my files so that they follow my namespace (on sites/configurations that allow me to do this). Once I can use PHP 5.3, that means I can both stick to that rule and use autoload.

In this case, the files would be, for sake of example:
com/example/web/WebService.php
com/example/parsers/CSVParser.php
com/example/text/Formatter.php

In PHP 5.3, with the autoloader:
Code php:
<?php
use \com\example\web as web;
use \com\example\pasers\csv as csv;
use \com\example\text as text;

namespace myapp;

spl_autoload_register(function($class) { require_once str_replace('\\', DIRECTORY_SEPARATOR, "$class.php");
}); // Closures (available in PHP 5.3)

try {
$csv = new csv\CSVParser(); // Do stuff } catch (csv\InvalidCSVDataException$e) {
// Do other stuff
}

Note: I don't know how to alias the classes (and get rid of "csv\", etc.) and get autoloading to know what to load.

23. Thanks for the insights.

Two things.

1 Public users: just a clumsy way of me meaning at runtime if something caused the wrong $ws type object to be loaded into the CSVparser, the whole thing would just stop with a fatal error. Maybe I am confused by the warning message I got "Catchable Fatal Error ... " which suggests that it is catchable, if this is so, can one catch it? and how? I realise the benefits of type-hinting (class hinting) for library makers and users of those libraries, but don't see any benefits in terms of making some kind of recovery from this fatal event if you have display_errors off. 2 This question doesn't really have a "right answer" at the moment because we're on the verge of migrating to 5.3 (or at least in the future). Thats Ok though because I am just trying to create some good guidelines for myself in order to habitually use throw new Exception from now on as I develop. I am sure I will work out in good time the reasons why I then need to break out of those rules in order to get the best out of my code, probably by looking at other good coding practices, or by noticing duplication/waste. Up until now everything I have read about Exceptions has seemed counter-intuitive, no matter how many times I read them, so I am pretty pleased. 24. Originally Posted by Cups 1 Public users: just a clumsy way of me meaning at runtime if something caused the wrong$ws type object to be loaded into the CSVparser, the whole thing would just stop with a fatal error.

Maybe I am confused by the warning message I got "Catchable Fatal Error ... " which suggests that it is catchable, if this is so, can one catch it? and how?
Unfortunately, by "catchable" it does not mean that an exception is thrown that you can catch. It merely means that it's not entirely fatal, because you can still handle it using PHP's error handling (unrelated to exception handling): http://php.net/set_error_handler

You can't rely on that to handle the error within the same flow of the code though, because that error handler is global. However, you can turn all of PHP's "catchable" errors (and warnings and notices) into exceptions. You can find code for that on this page:
http://php.net/ErrorException
Be aware that, with this, *everything* can now wreak havoc on your code unless everything is aware of these exceptions.

Originally Posted by Cups
I realise the benefits of type-hinting (class hinting) for library makers and users of those libraries, but don't see any benefits in terms of making some kind of recovery from this fatal event if you have display_errors off.
It will still stop the page even if you turn off display_errors.

Are you also asking for situations where you would want to try to catch this?

---

To sum up, you should throw an exception to make sure something doesn't go wrong down the road later on. You also can't anticipate certain runtime exceptions (like connecting to a socket or database), so throwing exceptions allows the library user to safely handle any potential error.