Ask a Jedi: CFC Scope Question

This post is more than 2 years old.

Jason asks:

I know it is important to ALWAYS var scope your variables in your CFCs my question is, is there a difference between these two cfset statements?

<cfset var myVar = "" />

<cfset variables.myVar = "" />

It is indeed very important, and there is a world of difference between those two lines of code. I cover this more in my CFC Scope Reference, but the basic difference is that your first line of code creates a variable that will only exist for the execution of the method. You use this for any variable you create in the method, and be sure to not forget things like loop counters, query names, etc.

The second line creates a global variable the CFC. Anything in the variables scope is available to every method of the CFC. I'll typically use the variables scope for configuration information, like a DSN, so all my queries will use datasource="#variables.dsn#". You would definitely not want to use it for things you intend to just be in the local method.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Jason Dean posted on 3/18/2008 at 8:41 PM

Ray,

Thanks, that answered my question perfectly. And now that it is explained, it makes perfect sense. i can;t believe i didn;t see it before.

Jason

Comment 2 by Raymond Camden posted on 3/18/2008 at 8:45 PM

Don't feel bad. CFC variables scopes is something that can be tricky to developers just getting into it.

Comment 3 by Jim Ruzicka posted on 3/18/2008 at 9:54 PM

Another good one:

<cfset var myVar = "" />

and

<cfset var.myVar = "" />

Are these two statements the same within a cfc?

Comment 4 by Raymond Camden posted on 3/18/2008 at 10:03 PM

Nope, unfortunately, unlike the other scopes, the Var scope isn't a "named" scope, so you can't do var.x, and you can't structKeyList it, etc. Some people use something like this:

cfset var local = structNew()

and then use local.x, local.y, etc. This means less var scoping and makes it a bit more obvious that a variable is a local var, but personally I don't care for it.

Comment 5 by Edward Johnson posted on 3/18/2008 at 11:29 PM

What scope are variables that are created by tags like cfloop index="somevariable"?

Can Should you

<cfset var intx = 0>
<cfloop from="1" to="#q.recordcount#" var=intx>

so that it's in the local scope, or doesn't it matter?

Comment 6 by Raymond Camden posted on 3/18/2008 at 11:31 PM

Yes, you need to var scope loop iterators. _Anything_ that makes a variable needs to be var scoped. For example, cfquery name="foo", that will end up creating a query named foo, so you need to var scope it.

Comment 7 by Dan Sorensen posted on 3/18/2008 at 11:58 PM

I know Adobe needs to keep this style around for backwards compatibility, but I wish they could introduce new scope names that were easier to read and remember for this purpose.

...Then again, maybe they don't do that for some reason that I'm not aware of. So until then, just one of those things I must keep memorized.

Comment 8 by Akira posted on 3/19/2008 at 12:03 AM

Do you need to var scope queries that do not return values (insert, update, delete)?

Var scoping them just seems kind of... silly.

Comment 9 by Raymond Camden posted on 3/19/2008 at 12:09 AM

Akira, if you don't use a name for your cfquery (did you know names were optional?) then don't var scope it.

var scoping may be silly, but it's used in other languages as well.

Comment 10 by Josh Nathanson posted on 3/19/2008 at 1:39 AM

Definitely var scope your index variables in loops. I was getting an intermittent error for a while that I finally tracked down to just exactly that issue.

Comment 11 by Aaron Longnion posted on 3/19/2008 at 2:01 AM

some other easy ones to forget are cfsavecontent and cffile variables. It's good to be able to manually look at your cfc functions and fix ones you forgot, but I like to also run http://varscoper.riaforge.org/ fairly often to make sure I didn't miss anything.

Also, when you have a cffunction with a lot going on in it, it's sometime preferable to do cfset Var local = StructNew() right below your arguments, and then prepend all your function-"local" variables with "local." to ensure you don't miss anything. Usually, your functions should be small enough that it doesn't get that complicated, but the real word isn't always so simple... ;)

Comment 12 by Akira posted on 3/19/2008 at 2:10 AM

Ray, no I did not know. I learned it that way and I should read the documentation more carefully. :)

What I meant by silly is that everything should be local unless specifically made global... it just bugs me a little.

Comment 13 by Akira posted on 3/19/2008 at 3:47 PM

Ok, so I checked the documentation again, and it says that name is required for cfquery. However, when I tried a query without a name, it did not break.

Thanks for the tip Ray.

Comment 14 by aadams posted on 4/29/2008 at 9:43 PM

Is there a way to var scope a dynamic variable name? I thought this should work, but doesn't (cfmx7):

<cfset var "#arguments.passedInVariableName#" = "" />

or

<cfset var setVariable(arguments.passedInVariableName,"") />

Comment 15 by Raymond Camden posted on 4/29/2008 at 11:22 PM

No, but just use a struct.

cfset var local = structnew()

cfset local[anythinggoes] = "foo"

Comment 16 by aadams posted on 4/30/2008 at 12:49 AM

Thanks Ray. I really don't use dynamic names much, but just ran into a situation where I was using someone else's cfc that did this and was getting all kinds of fun variable "sharing" going on.

I've since just statically renamed these variables, but your suggestion would have been just as well, if not more elegant.

Comment 17 by aadams posted on 4/30/2008 at 2:00 AM

After posting the above I realized that the local struct idea would not have worked in my case (unless I'm mistaken). The dynamic variable names in this case are used for cfquery calls within the function (i.e. <cfquery name="#anythinggoes#"...>).

If you use local[anythinggoes], (i.e. <cfquery name="local[#anythinggoes#]"...> ) CF throws an error because the name local[theactualvalue] "is not a valid ColdFusion variable name".

I may be wrong, but if you do <cfquery name="#local[anythinggoes]#"...> the query results would not be locally scoped since #local[anythinggoes]# would just be a placeholder for the real variable name.

Like I mentioned before I'm now just using a static name for the query and that is fine (and probably the only way to do it). In this case, the dynamic naming of queries is not for referencing the query object itself (inside or outside) of the function, but is simply so that debugging output displays the descriptive name for the query. For instance:

<cfscript>
myQuery = queryCFC.read(sql="select * from orders", name="getAllOrders");
</cfscript>

The debugging output would show the query name as "getAllOrders". petty I know.

Comment 18 by Raymond Camden posted on 4/30/2008 at 2:01 AM

Why not just do

cfquery name="mydata"
local[dynamicnamehere] = mydata

Comment 19 by aadams posted on 4/30/2008 at 2:07 AM

That defeats the purpose. The goal was to name the query for debugging output purposes. I'm better off just keeping the static name rather than passing back the query to the local struct.

Comment 20 by Raymond Camden posted on 4/30/2008 at 2:12 AM

Ah, I missed that. Why not use the result= attribute to get the debug info? :)

Comment 21 by aadams posted on 4/30/2008 at 3:09 AM

Good idea, but I'm looking at the CF debugging output, which still shows the actual query object variable name and not the result attribute value. Also, since I var scope the query, I cannot see the result struct outside of the function, and would then have to put a cfdump (our output) inside the function and turn output="true" on the function. I don't like the taste of that.

Maybe there's something I'm missing?

Comment 22 by Raymond Camden posted on 4/30/2008 at 3:18 PM

Nope, you aren't. If you want the debugging then you are kinda screwed there.

Comment 23 by aadams posted on 4/30/2008 at 7:25 PM

That's usually my case :) This ones not a biggie, but I'm glad to have my sanity confirmed by a Jedi.

Comment 24 (In reply to #4) by Charles Robertson posted on 10/28/2015 at 9:22 PM

Why don't you care for it Raymond? Just interested. I use var local = StructNew() or var local = {}. It is a great time saver and provides a descriptive way of telling other developers that the variable is local to its method...

Comment 25 (In reply to #24) by Raymond Camden posted on 10/28/2015 at 9:24 PM

Um... I don't know. 8 years ago was a lifetime ago. ;) As it stands, "local" is a real scope now that equals the var scope. CF should have done it this way to start off. Now I'd have no problem using local.x, y, etc since it is just the var scope.

Comment 26 (In reply to #17) by Charles Robertson posted on 10/28/2015 at 9:26 PM

<cfquery name="local.query" datasource="#variables.dsn#">

Works perfectly. I use it all the time...

Comment 27 (In reply to #26) by Raymond Camden posted on 10/28/2015 at 9:27 PM

Err... yes. Because local equals var in newer versions of ColdFusion. Please make note of the age of this post. :)

Comment 28 (In reply to #25) by Charles Robertson posted on 10/28/2015 at 9:49 PM

Sorry. I just noticed this post is 8 years old. I guess if you use, var local = StructNew(); It protects against backward compatibility and just produces a harmless empty structure in CF9+

Comment 29 (In reply to #27) by Charles Robertson posted on 10/28/2015 at 9:55 PM

Point taken. I only just realised how old this post was...

Comment 30 (In reply to #28) by Raymond Camden posted on 10/28/2015 at 9:58 PM

I'm being picky, but my understanding is that var local = structnew() in 9+ won't do anything, it is basically ignored, since local is a scope and is itself the var scope. So technically it isn't making a new struct.

As I said - picky - and I could be wrong.

Comment 31 (In reply to #30) by Charles Robertson posted on 10/28/2015 at 10:16 PM

You are probably right. I guess I am thinking if a client wants to use codebase from a CF9+ project on an older application server, then creating these benign structures might come in useful. But this is pretty obscure.