An anonymous user (hey why not share your name?) asked this today:
I'm working more and more with cftry/cfcatch, but I'm still finding it confusing as to when to use a <cfrethrow> tag and the <cfthrow> tag. When would I use each?
This is a good question. I mean, we (developers) spend most of our time browsing blogs... err I mean trying to prevent errors. Why in the heck would you generate an error on purpose? Let me tackle each one and discuss why they would be used.
First off - why would you use cfthrow? In case you don't know, cfthrow lets you raise an exception. You can specify the exception type, message, detail, and other settings. Why would you do this? There may be cases in your business logic where it makes sense. A classic case is usernames. You normally do not want to allow multiple users with the same username in the same database table. Therefore, your "AddUser" logic may have logic that checks for an existing user with same name. If you find one, what do you do? Well, you could simply raise a flag. I've seen some developers who like to return structs from methods and store all kinds of information in them. They will store a return code, a return message, etc. Personally, I don't care for this. I think if your intent is to show that something has gone wrong, than an exception makes perfect sense. I know my readers will argue back and forth on this, but that's my opinion.
The typical place I will use cfthrow is inside CFC methods. My calling code will then use try/catch where appropriate. If you want an example, you can download Soundings and check out survey.cfc. (And other CFCs in the package.)
So why use rethrow? I think the example livedocs provides is a pretty good one. I'm going to crib their example code. (Adobe, if you mid, just let me know.)
<h3>cfrethrow Example</h3>
<!--- Rethrow a DATABASE exception. --->
<cftry>
<cftry>
<cfquery name = "GetMessages" dataSource = "cfdocexamples">
SELECT *
FROM Messages
</cfquery>
<cfcatch type = "DATABASE">
<!--- If database signalled a 50555 error, ignore; otherwise, rethrow
exception. --->
<cfif cfcatch.sqlstate neq 50555>
<cfrethrow>
</cfif>
</cfcatch>
</cftry>
<cfcatch>
<h3>Sorry, this request can't be completed</h3>
<h4>Catch variables</h4>
<cfoutput>
<cfloop collection = #cfcatch# item = "c">
<br>
<cfif IsSimpleValue(cfcatch[c])>#c# = #cfcatch[c]#
</cfif>
</cfloop>
</cfoutput>
</cfcatch>
</cftry>
Notice that the code uses try and catch to run a database query. There is a cfcatch block which specifically catches exceptions with type="Database". However, they do not want to handle cases where the SQL State is not 50555. (Whatever that is.) By using cfrethrow, they can say, "Oops, you know, we caught this exception, but upon further review we have decided it is really someone else's problem. Thanks. Call again." Basically, the rethrow is a way of "changing your mind" about catching the exception. To be honest, I don't think I've ever used this tag.
Archived Comments
We have used cfrethrow to throw a different sort of custom exception when a plain vanilla exception occurs. Say for instance that for database exceptions and one other sort of exception, I want to show this error page, but for all others, show this one. You catch the exceptions, and if it is one of your two, throw a different exception, otherwise, rethrow and let your error handling template take care of it.
I use rethrow all the time in a similar situation to the one you described.
I think the possibility to throw errors is necessary for any (modern ?) programming language. Why? Because return values from methods should return something for what the method was made for - and nothing else. I totally agree with your opinion. It's time to forget those old C days with negative numerical values as return statements if an error occured.
I recently used cfrethrow to help with debugging. I was running individual LDAP processes on 38,000 records, and getting an error halfway through. However the LDAP error was pretty cryptic. So, I caught the error, logged the details of the current record being processed, then rethrew the error to let standard error handling deal with the error. I was then able to figure out the error based on the content of the record.
I use <cfrethrow> to help debug an application. Often I will catch specific exceptions and handle them appropriately, but will also have a <cfcatch type="any"> to handle unexpected exceptions. The user gets a friendly "An unexpected error occurred" message, but the details are hidden. Within these <cfcatch> blocks I will have the following:
<cfif session.showdebug><cfrethrow /></cfif>
When I am debugging a problem I can turn on my showdebug flag and see the raw exception information.
i use cfrethrow within my cfc's that are called from flash remoting. this allows me to catch the error, log it, email it (or whatever) and then rethrow the error to the result handler in the actionscript of the caller which has it's own handler for errors (unlike a typical cf page where you may redirect to a custom error page or what have you). if the exception is not rethrown (and the return type is configured properly) then the error is returned to the calling page which is certainly not desirable.