SitePoint Sponsor

User Tag List

Results 1 to 24 of 24
  1. #1
    Community Advisor silver trophybronze trophy
    dresden_phoenix's Avatar
    Join Date
    Jun 2008
    Location
    Madison, WI
    Posts
    2,827
    Mentioned
    34 Post(s)
    Tagged
    2 Thread(s)

    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. #2
    SitePoint Guru
    Join Date
    Jun 2006
    Posts
    638
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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. #3
    SitePoint Guru
    Join Date
    Jul 2005
    Location
    Orlando
    Posts
    634
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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. #4
    SitePoint Addict
    Join Date
    Jul 2007
    Location
    San Jose, California
    Posts
    355
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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. #5
    derrrp
    Join Date
    Aug 2006
    Location
    earth
    Posts
    923
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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.
    No, I REALLY dislike having to use Joomla.

  6. #6
    SitePoint Wizard
    Join Date
    Mar 2008
    Posts
    1,149
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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. #7
    Community Advisor silver trophybronze trophy
    dresden_phoenix's Avatar
    Join Date
    Jun 2008
    Location
    Madison, WI
    Posts
    2,827
    Mentioned
    34 Post(s)
    Tagged
    2 Thread(s)
    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. #8
    SitePoint Wizard silver trophybronze trophy Cups's Avatar
    Join Date
    Oct 2006
    Location
    France, deep rural.
    Posts
    6,869
    Mentioned
    17 Post(s)
    Tagged
    1 Thread(s)
    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. #9
    Follow Me On Twitter: @djg gold trophysilver trophybronze trophy Dan Grossman's Avatar
    Join Date
    Aug 2000
    Location
    Philadephia, PA
    Posts
    20,578
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Cups View Post
    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. #10
    SitePoint Wizard
    Join Date
    Mar 2008
    Posts
    1,149
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    @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:
    <?php
    function 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(40);
    // 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:
    <?php
    function 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(40);
    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:
    <?php
    function 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(452), 0);
    // How do you detect the error?
    //

  11. #11
    . shoooo... silver trophy logic_earth's Avatar
    Join Date
    Oct 2005
    Location
    CA
    Posts
    9,013
    Mentioned
    8 Post(s)
    Tagged
    0 Thread(s)
    @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;

    Logic without the fatal effects.
    All code snippets are licensed under WTFPL.


  12. #12
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    996
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    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. #13
    SitePoint Wizard silver trophybronze trophy Cups's Avatar
    Join Date
    Oct 2006
    Location
    France, deep rural.
    Posts
    6,869
    Mentioned
    17 Post(s)
    Tagged
    1 Thread(s)
    Quote 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. #14
    SitePoint Wizard
    Join Date
    Mar 2008
    Posts
    1,149
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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. #15
    SitePoint Wizard silver trophybronze trophy Cups's Avatar
    Join Date
    Oct 2006
    Location
    France, deep rural.
    Posts
    6,869
    Mentioned
    17 Post(s)
    Tagged
    1 Thread(s)
    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 ;  // public messages are handled
    $DBG // Pro messages appear

    function 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 its
    necessary."
    ;
     
    // 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:
    <?php
    include( "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 it
    class CSVparser{
        public 
    $orderedData = array();

        function 
    __constructWebService $ws ){
        
    $ord explode("," $ws->getData() );

        if( 
    count($ord) <= )
            throw new 
    Exception('Given bad or empty data');
               
        
    sort$ord );
        
    $this->orderedData $ord ;
        return 
    $ord ;
        }
    }

    // given an array, formats it using a tag name
    class 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?
    Last edited by Cups; Mar 10, 2009 at 07:35. Reason: edited code samples and the exception handler

  16. #16
    SitePoint Wizard
    Join Date
    Mar 2008
    Posts
    1,149
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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:
    <?php
    class 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
    There's already an InvalidArgumentException =)

  17. #17
    SitePoint Member
    Join Date
    Feb 2009
    Location
    Here, There, & Everywhere
    Posts
    10
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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. #18
    SitePoint Wizard silver trophybronze trophy Cups's Avatar
    Join Date
    Oct 2006
    Location
    France, deep rural.
    Posts
    6,869
    Mentioned
    17 Post(s)
    Tagged
    1 Thread(s)
    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 it
    class CSVparser{
        public 
    $orderedData = array();

        function 
    __constructWebService $ws ){
        
    $ord explode("," $ws->getData() );

        if( 
    count($ord) <= )
            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?
    Last edited by Cups; Mar 11, 2009 at 04:22. Reason: corrected the code example as indicated

  19. #19
    SitePoint Wizard
    Join Date
    Mar 2008
    Posts
    1,149
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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.
    Last edited by sk89q; Mar 10, 2009 at 17:45.

  20. #20
    SitePoint Member
    Join Date
    Mar 2009
    Location
    New Zealand
    Posts
    16
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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. #21
    SitePoint Wizard silver trophybronze trophy Cups's Avatar
    Join Date
    Oct 2006
    Location
    France, deep rural.
    Posts
    6,869
    Mentioned
    17 Post(s)
    Tagged
    1 Thread(s)
    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?
    Last edited by Cups; Mar 11, 2009 at 05:18. Reason: added post-deliberation comments

  22. #22
    SitePoint Wizard
    Join Date
    Mar 2008
    Posts
    1,149
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Cups View Post
    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?

    Quote Originally Posted by Cups View Post
    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.

    Quote Originally Posted by Cups View Post
    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).

    Quote Originally Posted by Cups View Post
    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. #23
    SitePoint Wizard silver trophybronze trophy Cups's Avatar
    Join Date
    Oct 2006
    Location
    France, deep rural.
    Posts
    6,869
    Mentioned
    17 Post(s)
    Tagged
    1 Thread(s)
    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. #24
    SitePoint Wizard
    Join Date
    Mar 2008
    Posts
    1,149
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Cups View Post
    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.

    Quote Originally Posted by Cups View Post
    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.


Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •