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
That is quite possibly the clearest, most consise definitions of these items/concepts I have read.
# Posted By Scott Stroz
| 2/8/06 4:43 PM
Watch that traffic come in, Ray. This is hella useful!
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.
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
Don't forget Client, Cookies and Request.
http://www.depressedpress.com/Content/Development/... has a good write-up on scoping.
http://www.depressedpress.com/Content/Development/... has a good write-up on scoping.
# Posted By Phillip Senn
| 2/8/06 5:42 PM
Thanks for this Ray.
It confirms what I'd suspected, but it's nice to see it laid out in a single place.
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
For those who want a Java parallel, you might add:
variables = protected
this = public
And Java Private doesn't exist in a CFC.
variables = protected
this = public
And Java Private doesn't exist in a CFC.
# Posted By Jeff Houser
| 2/8/06 7:29 PM
P.Senn, added.
# Posted By Raymond Camden
| 2/9/06 8:39 AM
Great list Ray! Quick follow up question: When/Why would you use a contructor function? Or, what about accessor functions?
# Posted By mikeD
| 2/9/06 8:41 AM
MikeD - I'll answer in a separate blog post later today.
# Posted By Raymond Camden
| 2/9/06 8:45 AM
this is a great post... but now I am confused about using "This" scope. I use it all the time (inside a cfc) and I have a separate instance for each time certain methods are called so that each user can work on a separate instance of a "system" or a "worklog" or an "employee" I pretty much picked up this method from the ColdfusionMX Bible. Create an instance, initialize it, use a form to make changes, then call the "Set" methods to save the form data to the instance, then call the commit method to save the instance to the database. Have I been doing it all wrong?
# Posted By Michael White
| 2/9/06 9:21 AM
Michael,
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?
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
Ray,
How about a "My Quick Refs" pod and slap tables like this into it so that they stay easily accessible over time.
Wiggy
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
Chris - that is freaky. That is exactly what I was going to do. I'm also going to write a cheat sheet for CF Regex, as I always forget things like how to do non-greedy regex.
# Posted By Raymond Camden
| 2/9/06 10:29 AM
Jeff, are you saying that using the This scope is bad form because your component methods can be bypassed and you "should" be forcing everything to go through the component methods?
# Posted By Michael White
| 2/9/06 4:39 PM
oops, second part Jeff:
or are you saying that you might inadvertantly clobber a variable you didn't mean to causing a "difficult-to-diagnose" problem?
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
so Ray, the order of privacy of variables in a cfc is:
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.
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
Yeah. By the way - I know fdolks may be a bit surprised by the comments layout. Yes - I am working on things and tweaking layout here and there.
# Posted By Raymond Camden
| 2/9/06 4:58 PM
I'm not saying that the "This" scope is bad form. It really depends what you want to do.
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.
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
Ray, re: cheatsheet for RegEx... Earlier in the day I printed out Pete Freitag's regex thingy:
http://www.petefreitag.com/item/517.cfm
great article from Dec. 2003, but maybe nothing's changed since then.
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
I was thinking something more simpler - basically ripping off livedocs's various tables of characters ($ == ...) into one page.
# Posted By Raymond Camden
| 2/9/06 8:04 PM
Would it be possible to give an example of encapsulation, with a CFC - or a a walk through, just no code.
# Posted By jim moran
| 2/9/06 9:55 PM
I'm not quite sure how to give an example of encapsulation without writing a book. These two articles I wrote for CFDJ might help:
http://coldfusion.sys-con.com/read/47203.htm (The concepts behind CFCs)
http://coldfusion.sys-con.com/read/47446.htm (A CFC example)
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
One useful trick I've picked up somewhere for var-scoping variables:
<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.
<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'm hoping someone will actually see this as I'm having difficulty understanding the session scope from the cfc's perspective.
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
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

