A reader just sent this in:
I'm getting a bit confused as the difference in variables used in components. This, Variable, Var, Caller, etc....Can you clear the fog in my head for me?
I talked a bit about scopes in CFCs before, specifically an entry on November 25th about Variables versus Var in a CFC. But now is probably a good time to write out a good list:
Scopes in a CFC
| Scope | Purpose/How it Works/Etc |
|---|---|
| Variables | The variables scope is available to the entire CFC. A value set in the variables scope in one method, or in the constructor, will be available to any other method, or the constructor, in the CFC. I typically use variables in much the same way I use Application variables in an site. |
| This | The This scope acts like the Variables scope in that it is "global" to the CFC. However, it is also accessible outside the CFC. So if foo is an instance of the CFC, and you do: foo.name = "Rabid" outside of the CFC, then you have just creating a key called "name" in the This scope with the value of "Rabid." You can also cfoutput the value of foo.name. Because of this accessibility, many folks recommend against using the This scope, and instead suggest relying on methods to set data (or get data) inside the CFC. These methods then write to the Variables scope. To repeat: |
| Var | Var scoped variables exist only for the duration of the method. You must use the var scope for any variable that should exist only inside the method, like query names, loop iterators, etc. Sorry to "shout" but the lack of var scoping is one of the trickiest things to debug when things go wrong. Unlike other scope, you do not prefix the scope name in front of the variable. |
| Arguments | The arguments scope consists of every argument passed to the method. So if the calling code did foo(name="King Camden"), then the foo method will have a variable called arguments.name. |
| Form, URL, Application, Session, Server, CGI, Client, Request, Cookie | These scopes act exactly as they do anywhere else. In general you should not use these scopes inside a CFC. When you do you are making your CFCs less portable between applications. |
| Caller, Attributes | Caller and Attributes do not exist inside a CFC. They should only be used inside custom tags. |
I think I covered everything here. Anyone think we need a CFC "Cheat Sheet" PDF?
Editors Note: I'm getting some good feedback on this entry. I'll be editing the entry from time to time instead of just posting comments, so revisit the entry.
Comment 1 written by Scott Stroz on 8 February 2006, at 4:43 PM
Comment 2 written by Steve Collins on 8 February 2006, at 4:56 PM
I've pointed back to it from acid.
And yes, PDF with this and other cogent information - with enough work (I'm happy to help), we could come up with a really useful CFC guide.
Comment 3 written by Phillip Senn on 8 February 2006, at 5:42 PM
http://www.depressedpress.com/Content/Development/... has a good write-up on scoping.
Comment 4 written by Matthew Wyant on 8 February 2006, at 6:30 PM
It confirms what I'd suspected, but it's nice to see it laid out in a single place.
Comment 5 written by Jeff Houser on 8 February 2006, at 7:29 PM
variables = protected
this = public
And Java Private doesn't exist in a CFC.
Comment 6 written by rd on 8 February 2006, at 8:37 PM
Comment 7 written by Raymond Camden on 9 February 2006, at 8:39 AM
Comment 8 written by mikeD on 9 February 2006, at 8:41 AM
Comment 9 written by Raymond Camden on 9 February 2006, at 8:45 AM
Comment 10 written by Michael White on 9 February 2006, at 9:21 AM
Comment 11 written by Jeff Houser on 9 February 2006, at 10:07 AM
It sounds like you're implementing things, for the most part, the way I would. The difference between "this" and "Variables" can be explained like this:
<cfcomponent>
<cfscript>
this.MyVar1 = "test";
variables.MyVar2 = "test 2";
</cfscript>
</cfcomponent>
now, in a page, you create the component instance:
<cfscript>
MyComponent = CreateObject('component','whatever');
</cfscript>
This is perfectly valid, as variables in the 'this' scope are public:
<cfoutput>
#MyComponent.MyVar1#
</cfoutput>
Your can set the value like this:
<cfset MyComponent.MyVar1 = "">
which completely bypasses your set method. In some cases, that could (potentially) cause problems in your compoment.
This, however, will cause errors:
<cfoutput>
#MyComponent.MyVar2#
</cfoutput>
Because the "MyVar2" is not public, and cannot be accessed directly outside of the component.
Does that help explain?
Comment 12 written by Christopher Wigginton on 9 February 2006, at 10:17 AM
How about a "My Quick Refs" pod and slap tables like this into it so that they stay easily accessible over time.
Wiggy
Comment 13 written by Raymond Camden on 9 February 2006, at 10:29 AM
Comment 14 written by Michael White on 9 February 2006, at 4:39 PM
Comment 15 written by Michael White on 9 February 2006, at 4:41 PM
or are you saying that you might inadvertantly clobber a variable you didn't mean to causing a "difficult-to-diagnose" problem?
Comment 16 written by Michael White on 9 February 2006, at 4:50 PM
Arguments: only available within the method
Var: only available within the method
Variables: available to all methods but only in the same cfc
This: available to all methods, cfc, and all other pages.
Comment 17 written by Raymond Camden on 9 February 2006, at 4:58 PM
Comment 18 written by Jeff Houser on 9 February 2006, at 5:19 PM
I prefer to keep my instance variables in a CFC private (in the variables scope), and then provide an interface for API (AKA List of Methods) for accessing this the information. This is what encapsulation is all about.
I don't think I explicitly said "you might inadvertently clobber a variable in the this scope and cause a difficult to diagnose problem" however I do believe that is the case.
Comment 19 written by Michael White on 9 February 2006, at 6:16 PM
http://www.petefreitag.com/item/517.cfm
great article from Dec. 2003, but maybe nothing's changed since then.
Comment 20 written by Raymond Camden on 9 February 2006, at 8:04 PM
Comment 21 written by jim moran on 9 February 2006, at 9:55 PM
Comment 22 written by Jeff Houser on 10 February 2006, at 7:08 AM
http://coldfusion.sys-con.com/read/47203.htm (The concepts behind CFCs)
http://coldfusion.sys-con.com/read/47446.htm (A CFC example)
Comment 23 written by Mark van 't Zet on 23 February 2006, at 2:38 AM
<CFSET VAR local = StructNew()>
Everything prefixed with "local." is now var scoped. Very easy for iterator vars and queries one tends to overlook:
<CFLOOP index="local.i" ..>
<CFQUERY name="local.q" ..>
It just doesn't work with Query of Queries, the following throws an error:
<CFQUERY name="local.q2" dbtype="query">
SELECT * FROM Local.q
</CFQUERY>
Seemingly QoQ only works on hard defined scopes such as Caller, Variables, etc.
Comment 24 written by Joel Johnston on 1 April 2007, at 11:28 PM
I have a site that has a cart.cfc with setters and getters for various functions. The access of this cfc is set to package and I'm using a facade cfc to call cart.cfc's various methods.
Within this cfc I set a structure called session.cart. All works well from coldfusion, I can add, remove, etc items from that structure.
Enter Remoting: When I call the facade (or the cart.cfc's) methods from remoting, it errors saying that the session variable is undefined.
I was of the understanding that the facade cfc could call the "internal" cfc and scopes such as application and session would persist. Is there anyone out there that has tackled this issue and can give me advice?
Extra Site Info:
Fusebox 4.1
CFMX7 on Linux with Apache-2.0.54
J2EE sessions enabled
Thanks in Advance!
Joel
[Add Comment] [Subscribe to Comments]