I think this disscussion on exceptions is still interesting.
I have put considerable thought into why or how they should and shouldn't be used and honestly I can't come to a solid decision -- so in my opinion it's worth disscussing further.
I think the reasons to use exceptions are misunderstood. They are a tool, but I think they serve different roles in different languages and environments.
The biggest problem I have with exceptions, is the name is something of a misnomer, at least when used liberally in PHP.
People use the terms exception and error like they mean the same thing --- which is what I think causes so much argument and further propagates misunderstanding.
In my experience, there are two types of errors:
1) Userland
2) Environment
Userland errors are caused by the direct actions of a user. Such as creating a member record in a database but passing invalid arguments through the form. If you submit an email which isn't RFC format, that is an error and the user should be notified of such so they can take corrective action.
Environment errors are those which are unpredictable and cannot be circumvented by the end user. Errors which are typically caused by misconfigured environment, such as missing config files or a downed database.
I'm not sure I like the definition environment error, but perhaps:
- Expected
- Critical
Regardless, I think when people advocate that exceptions are to be used for exceptional situations -- what they really mean is, they are to be used for critical errors only. AT least that is what I meant when I argued my case about 'exceptional' situations and what they really mean.
I also think that is mostly a cultural issue. Having come from a C++ background, exceptions were typically used in critical situations when there was no chance of recovery -- they offered a graceful exit.
However, not all habits from C++ should or need to apply to PHP. For instance, hungarian notation, while it makes sense in C++ doesn't transcend into PHP. Likewise, exceptions in PHP are perhaps a tool which can be used in non-critical situations.
I remember back in the day when it was cool to use the bitwise shift operator for faster divide by two. That is not what the shift operator was introduced for, but it was a tool and it worked and it was faster -- although confusing to the uninitiated developer. Ok maybe that was a bad example. The point is, I think PHP developers are forward thinkers. We can focus more efforts on proper design and interesting use of tools, than is feasible in C++.
If you agree with my assesment above, in that there are two types of errors, then it is a matter of deciding whether an exception should be used for both or just one -- the critical.
Originally, I reserved the use of exceptions for strictly critical errors. Why? Because I had a single try/catch in my index.php which acted as a centralized error handler which sent me an email when anything went sour (it's of no immediate interest to me when a user enters invalid informaiton -- thats what log files are for). Additionally, the term "exception" tells me, that indeed, they are to be used in "exceptional" circumstances. What is "exceptional"?
forming an exception or rare instance; unusual; extraordinary: The warm weather was exceptional for January.
I wouldn't personally define a user generated error exceptional, so for that reason, I had a hard time using exceptions in anything but critical errors. Then I thought about it, argued my points and listened to others, tried it and convinced myself that exceptions could be handy and offer a better solution to error handling.
1) Wrapping your code in try-catch is so clean. I love simplicity and being explicit makes things simple. Using conditionals to test for errors makes for more difficult to follow source code. Using a try-catch is very clear about what is going on.
2) Returning error codes is not always ideal. Consider the following:
http://en.wikipedia.org/wiki/Semipredicate_problem
Of course, there are negatives to every positive.
The problem with using exceptions for userland errors, is that PHP implements what are often called terminate type exceptions, the alternative being resume. When an exception is thrown, it haults your application and makes it (sometimes) impossible to re-enter and/or recover. If you wish to display an error message to your end user and have that incorporated into your application design, you need to figure out a way to re-enter your application from the catch block.
Secondly, because exceptions result in pre-mature termination, this can also introduce problems when you don't wish to display an error message, but just continue as normal.
I implemented a model, lets call it Members.
Code: Select all
class Members{
function create($email, $address)
{
if(!validEmail($email)){
throw new Exception('Invalid email');
}
// Do stuff ...
}
}
This code worked fine and made error handling very clear from the caller perspective. However, when I called the above method inside a loop while importing mass Members.
Code: Select all
foreach($members as $member){
$model->create($email, $address);
}
I was interested in only logging errors and not directly displaying them to end users -- because were importing potentially 1000's of members it doesn't make sense to display the error one by one and because the records are being inserted into the database, simply stopping on the first error and displaying a message didn't make much sense either. Because of the exception being thrown inside create() I had to deal with this situation. Originally I used error codes to indicate the success or failure of the create() and the import worked fine -- when I switched to exceptions I needed to re-solve the problem by first filtering the members before iterating them and calling create(). Just a bit of a PITA.

The alternative was to implement some re-entry technique -- which was just more confusing so I settled on the former.
Ultimately, I prefer clarity over anything. Using exceptions separates my application logic from it's error handling (exceptional, critical, user generated, etc) and thus makes it easier to follow.
What I did discover after introducing exceptions into userland errors, was what I was really trying to do was provide a event of sorts similar to how events in javascript bubble up to the nearest event handler. Essentially I was using the exceptions as a message transport and was not *really* handling the error, so much as I was trying to relay information up to a spot that could display my error to my users.
Exceptions when used in critical situations, are occasionally attempts to recover from disaster (at least I've heard them touted like that). When a database is not connecting, one might try an alternative, and correct the situation programatically. When a user enters an invalid email, the onus is on the user to correct the problem, not the software (usually). That is just another distinction I think some people make and others don't when trying to determine whether to use exceptions or not.
What I have done, is declared a special "final" class called "Message_Exception" which is thrown from inside my models and caught by each action controller. It is my attempt to distinguish between "expected" errors such as those caused by user error and environment errors. Like I said, I dislike the term "exceptions" and I think it is that which causes all the arguments. I think it made sense to use that term in the context of C++ but in PHP not so much. Just some plain old bad inheritence on the part of the language designers.
I think the mechanism it provides is wonderful but there are minor adjustments I would make:
I would perhaps introduce, something of a event model. Instead of throwing an exception inside model code when a user enters the wrong data, I would rather "raise" or "fire" an event to notify the system that an end user error occured. The event would not hault the application but instead cause the code to jump out of context, be processed and optionally (possibly) re-enter where it left -- resume style.
When the error was critical, like in the situation of a downed database, I would prefer to throw an "exception" which was similar to raising an event, however the exception would need to be handled (unlike events - which would prevent the mass import problem I encountered) or it would result in an ugly PHP fatal error. Because the situation is critical, the chances are that you won't need to re-enter so termination would be fine.
I just want to make one more point.
Programmers typically use C++ for Window'ed applications. Windows, as you know, intrinsically supports an event model (actually it's a messaging system but when wrapped in C++ frameworks like MFC it's called an event -- Linux has something similar but they are refered to as signals). When a user enters in bogus information, the developer does not need to resort to throwing an exception, because they could use the built-in event model to indicate to the system the error has occured. In PHP (typically -- unless you build Window'ed applications) we have no event model, so throwing an exception is the next best thing to emulating the bubbling effect of such as mechanism.
I think that is yet another reason some developers are so hard pressed to use exceptions for userland errors in PHP. They are so used to simply display a message box directly as the error occurs they fail to see the usefulness of exceptions in the execute-terminate environment of a typical PHP application -- at least I was certainly guilty of that.
I think it's pretty interesting actually, how developers have cultural differences which sometimes dictate their best practices. C/C++ developers are so intent on writing fast code, they want to avoid occassional best practices for the sake of speed. Java developers want to abstract everything, which often leads to additional complexity. Overhead is not an issue, as most application written in Java are of the educational type, as opposed to C++ and it's commercial viability. No offense to Java geeks but most commercial applications are done in C++ (still) although I agree that gap is closing daily (with C# assuming a large role).
The point is, I'm not sure if anyone is right or wrong in their use of exceptions. Although I do think they are not fully understood -- just read articles available and you'll see that 99% of the articles are pretty much re-hashed content from authors like Bruce Eckel or other C++ experts. I think developers learn of exceptions after already becoming familiar with programming and they encounter one of two articles. One which advocates using them all over the place or one which says they are only to be used in "exceptional" un-expected situations. Old habits die hard and so, depending on what language you come from, your mind is already made up by the time you find yourself in PHP.
I think we should compile a comparison table and generate a document of best practices when using exceptions, drawing on real world examples like I've given above of when exceptions make sense and maybe when an alternative is better. Although I must say, I prefer using exceptions and would rather just filter the data before passing it to the iteration code.
p.s-Sorry for the short story -- I'm poet and didn't even know it. I just choose to write my emotions down in a binary fashion.

p.s.s-I realize I used the world "I think" about 50 times -- sorry for that too.
Cheers
