Re: Exception misinformation

From: Date: Tue, 06 Jul 2004 23:26:10 +0000
Subject: Re: Exception misinformation
References: 1 2  Groups: php.pear.dev 
Request: Send a blank email to pear-dev+get-31682@lists.php.net to get a copy of this message
Klaus Guenther wrote:
Here's an example [that I think I've given before]: function hydrate(ResultSet $rs) { try {
    $this->setName($rs->getString(1));
    $this->setEmail($rs->getString(2));
    $this->setLoginCount($rs->getInt(3));
    $this->setPicture($rs->getBlob(4));
    $this->setLastLogin($rs->getTimestamp(5));
    $this->setSignature($rs->getString(6));
    $this->setPassword($rs->getString(7));
} catch (SQLException $e) {
     throw new PropelException("Error populating Person object.", $e);
} }
So... if an exception is thrown, does the block complete execution? or does it stop as soon as the exception is thrown? If the former is true, you need to try for exceptions whenever something important happens.
Yes, you are correct (as you noted below), but your conclusion isn't quite correct. Any exception will immediately traverse up the stack until it finds the first catch block. (That could be several function calls higher up the stack.) You use the try/catch blocks at very points in your code to establish transaction units that are meaningful. In the hydrate() example above, I don't care which method threw an exception. Any error in that process indcates an error of the task on the whole and needs to be wrapped as an "unable to populate object" exception and thrown up to the calling code. That PropelException that I throw in that example will be caught by the next "transaction" point in the process. Thinking of exceptions in terms of nested transactionsis probably easiest. It's easiest for me, but then I use this stuff largely in db components (e.g. Propel) applications, so transactions are a natural fit. More generally you can think of try/catch blocks as delimiters for salient (meaningful) tasks. But you don't want to go overboard with try/catch either for performance reasons; so I tend to try to find a coarse-grained-but-meaningful balance. In some cases (like your example below) you may use a more fine-grained try/catch block to explicitly ignore errors because it would be much more work to check for them first.
For example, in a DB script I have, I need to be able to roll back anything I've submitted to the DB if something goes wrong. (I'm using linked tables.) Exceptions would be a huge mess if they allow my script to first populate all the data before I get notified that I'm in trouble. This wouldn't make sense to me. However, if the latter is the way it works, and an exception is simply notifying me that something minor failed that I don't care about (e.g., if I passed a roman numeral with illegal characters), then it breaks my whole script until I fix the input (which I may or may not have control of, esp. if I'm simply parsing existing data and I don't care if something minor fails). Exceptions force the developer to group calls into one break/all break groups. And while for something like a failed DB connection would amply justify an exception, there are very many errors that don't.
Luckily exceptions won't allow you to populate all data. As Justin mentioned transactions & db rollbacks are where exceptions really shine. If you don't care if something minor fails, then you can explicitly let it fail using try/catch blocks. Really in the example you provided the only exceptions that would be thrown would be the result of being unable to execute a database query. The parsing of your data has presumably already happened. If your database query fails, then I assume you do actually want to be alerted via exception so that you can rollback. In practice what you are describing either wouldn't happen or would be indicative of needing to fix your application design. From my experience I can say with confidence that exceptions + db transactions are a match made in heaven.
So the way I see it, try() catch() is a lose/lose situation depending on what you want to do with it. That's why an error stack is so important and notices, too.
Yeah, but I don't think the way you see it is the way it works. Try building an application with exceptions.
Btw, since writing the above I was chatting on IRC and was told by meebey that when an exception is thrown (and filters down to the level of the try), execution is halted and catch is envoked. This is bad in many cases as I've mentioned above. Overuse of exceptions will make PEAR less than usable. Is that a death knell I hear in the distance?
I don't know what you hear, but you sure are dramatic about it :) The only thing that you've illustrated by your "many cases" above is that if you cram all of your logic in one layer & one big try/catch block then exceptions will not serve you well. I agree; that's arguably very bad application design. If you group your logic into tasks then exceptions will fit very naturally, since a failure of a part of the task almost always means a failure of the task (and if not, you can explicitly allow failure using fine-grained try/catch). Hans

« previous php.pear.dev (#31682) next »