CJ had a good set of questions concerning the request scope:
Ray - can you explain the request scope? Over the years, I've used it in various ways...but never fully understood it. Since it only lasts for the duration of the page request...what's the biggest difference between <cfset variables.myVar = "foo" /> and <cfset request.myvar = "foo" />?There are numerous questions here, so let me try to hit them up one at a time:In the past, in my Application.cfm, I would duplicate() the application scope into the request scope so as to not have to worry about locking application vars throught my code.
Well, I've inherited an application that, in the Application.cfm, is setting application variables, request variables, and even local variables in various places.
So my question boils down to this... Is there still a reason to duplicate() the application scope into the request scope (as opposed to just creating the vars in the request scope to begin with)? Is there a significant difference between setting variables into the request scope and just setting them into the local scope (specifically in the Application.cfm)?
I need to clean up this file, and I'd like to stop setting variables in so many different scopes (I like consistency and would rather see them set in one place...either application, request, or local). Or might there be a reason that they're being set in different scopes?
Is there still a reason to duplicate() the application scope into the request scope (as opposed to just creating the vars in the request scope to begin with)?
I would say no. One of the reasons people would duplicate the Application scope in the "old days" is that you needed to cflock each and every instance of a shared-scope variable. You mentioned this above. This made using Application variables as simple settings a bit of a pain. By simply duplicating the data to the request scope you saved yourself a heck of a lot of typing later on. Thankfully the MX days have put excessive locking behind us. (You kids don't know how lucky you have it...)
Is there a significant difference between setting variables into the request scope and just setting them into the local scope (specifically in the Application.cfm)?
Not knowing the exact guts of CFML and how it's creating the local variables and request scope, I'd hesitate to say anything for sure, but my gut reaction is no. From a memory and performance level, it should be roughly the same.
So when and where would you use the request scope? Obviously my readers will chime in with their ideas, but I typically use it for UDFs. I'll have a UDF file that looks something like this:
request.udf = structNew();
function doIt() { return true; }
request.udf.doIt = doIt;
This is included by my Application.cfc and then I call the udfs in my code like so:
<cfset result = request.udf.doIt()>
Why bother? Well one nice thing is that if you use custom tags, you have one main way of calling UDFs. If the UDFs were just in the variables scope, my custom tags would need to do this:
<cfset result = caller.doIt()>
Ugly, right? (And yes, I know I've done this before.) Not only is it ugly, it is potentially dangerous. If your custom tag ends up being called by another tag, the caller syntax won't work. Sure you could:
<cfset result = caller.caller.doIt()>
But that is even uglier. By just using the request scope, you have one place to load and use all your UDFs. Notice that I put the UDFs in a struct called "udf". That just helps me remember where stuff is, and I think it is a nice way to organize them.
One last note - if you do end up using the request scope, double check that you aren't doing "too much." Ok, I know "too much" is super vague, but if you are setting a few hundred variables in the request scope on every hit, you should consider using the application scope instead. I know I don't put CFCs in the request scope, since creating them tend to be expensive. For UDFs I haven't noticed much of an impact. (My sites typically will have less than 10 UDFs so your mileage may vary.)
One final note: I would almost never recommend using Application.cfm/cfc to set local variables. Nothing is more confusing then debugging an issue where you can't understand why some variable exists and it ends up it was created in your root Application file. The Application.cfm/cfc file should only be creating application, session, client, or request variables.
Archived Comments
I'll bite and give me 2 cents here (expect change).
Since CFMX7 with the application.cfc, the locking issues vanishing and components actually working correctly; I would say that the request scope is dead. I can't really see a reason to use it anymore. In the old days, I would use it for exactly what Ray said, UDFS. Today I put all my UDFS into a component and then throw that component into memory using:
<cfset application.function = CreateObject("component", "UDFS")>.
Why you ask. Because now I have one place to add / edit UDFS and I can include them into any other component I need them in. I also take any setting I'm going to be using throughout the application and put them into the application scope using:
<cfset application.setting.dsn = "myDSN">
All this stuff get done in the onApplicationStart(). Probably 90% of the CF programmers out there are doing the same.
One thing about Tony's comment. My issue with custom tags and how to "address" them would _also_ be solved by using the app scope as he described.
I use the request scope for one specific purpose in a few of my applications.
In a few of my applications, I have objects that I store in memory for each user. This makes things like session.user.getFirstName() really easy to use. The problem is that these applications need to be able to update the information about a user, and have it apply to ALL instances of the user cfc. To solve this problem, I copy a reference of my user cfc instance into the request scope at the beginning of each request. I copy it from an object cache manager that handles updating information and expiring the appropriate cache objects.
That might sound a little convoluted, but the end result is that my code has become much easier to maintain without session based side effects. I don't use this technique often, but when I need it, it's beautiful.
Sam,
It doesn't sound like you should be using a session variable if you need to 'update it' for all users of your application. Sessions, by definition, are user-specific.
Unlike Tony, I never used to use the request scope, but because of application.cfc have started to do so.
I would set 'local' variables in the variables scope, such as a dsn name, site URL, directory path, etc...
At some point (probably for legacy cflock reasons) I decided it didn't make sense to do this in the application scope and moved everything to the variables scope.
Since the variables scope of Application.cfc is no longer avaiable to the page (unless the onRequest method is used), I moved all such variables to the request scope.
Herre is a senario.
You build a framework that can call itself for event handlers. Each call stores the current call passed variables in "attributes" scope. Yet you want to have access to the iniating call attributes also.
Answer: Request for global scope. Attributes for more granular process calls.
Note: My goal is to have a feature ritch API, but not lose touch with originating request. I completely agree with using CFCs and think that there is still a place for custom tags. (Things like a better grid than the one the ships with CF. A grid that handles forms in HTML and has AJAX capability.)
To use or not to the use the request scope. That my dear friends is the question that plagues us today.
The answer is both clear and vague. The answer is simple though. ColdFusion provides you the choice for setting commonly reused variables and objects.
If you want the data or object to exist on just the current page, then albeit enjoy the request scope. If you want the data or object to persist application wide, have at it.
Each developer maintains his/her code. For a given situation it may be clear to use one or the other. If the decision is not clear and amorphous, choose the option you feel comfortable with and can maintain easily.
Ease of use is subjective to the developer.
Enjoy and blog on!
Teddy: Very much in agreement.
Jeff: My 'session' objects are 99% read only, but need to be able to update on demand when the underlying (persisted) data does change. I assume by your comment that you thought I was updating non-persistant information in my 'session' components. The only updating I do is persistant data, and I update from a management interface, not from any one of multiple user sessions.
Teddy,
The request scope 'persists' beyond the current page. It is avaiable to custom tags, CFCs, and User Defined Functions that the page calls. ( All our part of the 'request', but not necesarilly part of the 'page'). Minor semantics.
Sam,
I'm really confused with your usage.
You said that you update information about a user and have to update ALL instances if a CFC to reflect this updated information. If that is truly the case, then ALL instances of the CFC must have the same data. If ALL CFCs have the same data, why does each session need to store it?
Simplicity of code. The Session does not store an individual instance, but a reference to a single instance maintained in the application scope. By copying the reference (from my cache manager) to the session (or request) scope, I can use the object methods very easily. Retrieving the object from the cache manager on each request (and storing it in the request scope) allows the cache manager to decide when to reuse the cached copy and when to re-create the object and reload persisted data.
Hi,
I am still confused about the persistency of Request variable. The Doc says it only lasts for the duration of the page request. If I use CFLocation to other template, is it still persistent? If I submit a page to the action page either the same page or another page, is it still persistent? Thanks for the clarification.
When you cflocate, CF tells the browser to go to another URL. THerefore it is a new request, so no, it won't persist. When you submit you are making a new request, so no, it won't persist.