Ask a Jedi: Variable Scopes in CFCs
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.
Comments
# Posted By Scott Stroz
| 2/8/06 4:43 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.
# Posted By Steve Collins
| 2/8/06 4:56 PM
http://www.depressedpress.com/Content/Development/... has a good write-up on scoping.
# Posted By Phillip Senn
| 2/8/06 5:42 PM
It confirms what I'd suspected, but it's nice to see it laid out in a single place.
# Posted By Matthew Wyant
| 2/8/06 6:30 PM
variables = protected
this = public
And Java Private doesn't exist in a CFC.
# Posted By Jeff Houser
| 2/8/06 7:29 PM
# Posted By Raymond Camden
| 2/9/06 8:39 AM
# Posted By mikeD
| 2/9/06 8:41 AM
# Posted By Raymond Camden
| 2/9/06 8:45 AM
# Posted By Michael White
| 2/9/06 9:21 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?
# Posted By Jeff Houser
| 2/9/06 10:07 AM
How about a "My Quick Refs" pod and slap tables like this into it so that they stay easily accessible over time.
Wiggy
# Posted By Christopher Wigginton
| 2/9/06 10:17 AM
# Posted By Raymond Camden
| 2/9/06 10:29 AM
# Posted By Michael White
| 2/9/06 4:39 PM
or are you saying that you might inadvertantly clobber a variable you didn't mean to causing a "difficult-to-diagnose" problem?
# Posted By Michael White
| 2/9/06 4:41 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.
# Posted By Michael White
| 2/9/06 4:50 PM
# Posted By Raymond Camden
| 2/9/06 4:58 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.
# Posted By Jeff Houser
| 2/9/06 5:19 PM
http://www.petefreitag.com/item/517.cfm
great article from Dec. 2003, but maybe nothing's changed since then.
# Posted By Michael White
| 2/9/06 6:16 PM
# Posted By Raymond Camden
| 2/9/06 8:04 PM
# Posted By jim moran
| 2/9/06 9:55 PM
http://coldfusion.sys-con.com/read/47203.htm (The concepts behind CFCs)
http://coldfusion.sys-con.com/read/47446.htm (A CFC example)
# Posted By Jeff Houser
| 2/10/06 7:08 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.
# Posted By Mark van 't Zet
| 2/23/06 2:38 AM
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
# Posted By Joel Johnston
| 4/1/07 11:28 PM
