In part three of this primer, we discussed how an object's variables scope exists only within itself and is available to any function it contains. Now we need to cover how and why to make a variable only available to a single function.

John Jacob Jingleheimer Schmidt

His name is my name too.
Whenever my value's changed,
You can hear the people shout,
Why isn't this function giving me the right value?

One of the biggest problems when writing functions in objects occurs when two or more functions manipulate a variable of the same name. Since any variable that is not explicitly scoped is placed into the variables scope, not only can every function in the object read its value, every function can change its value.

Multi-threading rears its ugly head

The problem of a variable's value being changed unexpectedly may not appear while you're developing an application. However once your application hits production and the number of users increases, you'll begin to see the effects of having non-var-scoped variables in your functions as reports of invalid data come pouring into the helpdesk. This is especially true for objects that are stored in the server, application or session scopes.

Let's say you have a form.cfm that submits to form_process.cfm. While you're developing the form, on form_process.cfm, you create an instance of FormObject.cfc to handle the data from the form.

Since you've created an instance of the object every time the form is submitted, then the object's variables scope is available to the single thread that is processing the form's submit action. If ten users submit the form, then ten threads are created, each with their own insulated instance of FormObject.cfc.

Now you decide to place FormObject.cfc into the appliction scope so you only have to create it once, instead of every time that form is submitted. At this point, when ten users submit the form, ten threads are created and they all use the same instace of FormObject.cfc.

This means that ten threads are calling functions that can alter anything in the variables scope of the object. The more threads, the more possibilites that the data inside that object is not secure.

By var scoping your function variables, you can eliminate the possibility of the object corrupting its data.

What needs to be a function local variable?

Pretty much everything that is related to the function you are writing needs to be var scoped.

Placing a variable in the var scope

1. simple variables

2. Loop indexes

view plain print about
1<cffunction name="doLoop" returntype="numeric">
2
3    <cfargument name="b" type="numeric" required="true" />
4    
5    <cfset var x = 0 />
6    <cfset var y = 0 />
7    
8    <cfloop index="x" from="1" to="#arguments.b#">
9        <cfset y = y + x />
10    </cfloop>
11    
12    <cfreturn y />
13
14</cffunction>

3. Query names

view plain print about
1<cffunction name="getSomeRecords" access="public" output="false" returntype="query" hint="returns a record set">
2
3    <cfargument name="ID" required="true" type="numeric" hint="Some user ID" />
4    
5    <cfset var qRecords = "" />
6
7    <cfquery name="qRecords" datasource="#variables.DSN#">
8        SELECT id, label
9        FROM someTable
10        WHERE id = #arguments.ID#
11    </cfquery>
12
13    <cfreturn qRecords />
14
15</cffunction>

4. the "variable" or "returnVariable" attribute of any CF tag

view plain print about
1<cffunction name="readFile" returntype="string">
2
3    <cfargument name="filePath" type="string" required="true" />
4    
5    <cfset var fileData = "" />
6    
7    <cffile action="read" file="#arguments.filePath#" variable="fileData" />
8    
9    <cfreturn fileData />
10    
11</cffunction>

Can I var scope anywhere?

If you've worked with Javascript for a while, you may have seen the var scope already. Javascript allows you to var scope a variable anywhere in the function.

Javascript function with multiple var scoped variables
view plain print about
1function foo(a)
2{
3    var b = 10;
4    
5    for (var x = 0; x <= a; x++)
6    {
7        b = b * a;
8    }
9    
10    return b;
11}

Coldfusion requires that all var scoped variables be declared at the top of the function, after any cfarguments, but before anything else is done.

CFFunction with mutlple var scope variables
view plain print about
1<cffunction name="doLoop" returntype="numeric">
2
3    <cfargument name="a" type="numeric" required="true" />
4    
5    <cfset var x = 0 />
6    <cfset var b = 10 />
7    
8    <cfloop index="x" from="1" to="#arguments.a#">
9        <cfset b = b + x />
10    </cfloop>
11    
12    <cfreturn b />
13
14</cffunction>

Can I name a var scoped variable anything?

The only conflict in naming function local variables is that they cannot match any of the argument names for the function.

Invalid var scoped variable name
view plain print about
1<cffunction name="doSomthing" access="public" output="false" returntype="string">
2
3    <cfargument name="foo" required="true" type="string" hint="" />
4
5    <cfset var foo = arguments.foo />
6
7    <cfreturn foo />
8
9</cffunction>

Examples

Dave Shuck has a great example on his site: Thread safety example: Var scope your loop index in ColdFusion CFCs!

Tyson Vanek has another one: The REAL reason you need to var-scope your local CFC function variables

But I've already written a ton of code . . .

Fear not! Mike Scherberl has written a great tool called varScoper that will scan through your files and tell you which variables need to be var scoped in your existing code base.

Can we talk about specific objects now?

Yes, yes, yes. Now pipe down or I'll turn this Primer around and we'll go home.

The first object we'll discuss tends to spark a few fires in the Coldfusion community: The Gateway Object.

Put on your protective gear and let's head into the inferno.