Protecting your local variables
In our previous personalGreeting()
method, we included two separate functions, sayHello()
and getName()
, into the main method. This is not an uncommon practice, and is what you would expect when writing detailed components with relationships between its included functions.
One issue that can arise when developing in this way is when two or more methods contain a variable of the same name and the value of that variable is accessed or changed by one of the methods.
As an example, the following code contains two functions, baseNumber()
and multiplyNumbers()
.
While the cfcomponent
tag has been excluded in this example, this could also easily be turned into a CFC by wrapping the functions within cfcomponent
tags.
Listing 1.15 two user-defined functions
A cfloop
tag runs a loop from 1 to 10. The multiplyNumbers()
function accepts two arguments. In this example, these are both the index numbers of the loop. We want to multiply our baseNumber
value (argument 'a'), by 10 for each loop, creating a 10 times table list. To do this, the multiplyNumbers()
function has a hardcoded value (x) that is set to the value of 10.
The desired results you would expect from this code should be:
However, this is not the case. If you save the code to a .cfm
template and run it in your browser, you will get the following result:
This is clearly not the result you would expect. So what's happening to cause this issue? Let's take another look at our two functions:
Listing 1.16 examining the two methods
You can see that both functions have a variable called x
. The baseNumber()
function stores the value of the argument as the x
variable, which it returns into the multiplyNumbers()
function for use in the equation. The multiplyNumbers()
function also has a variable called x
, which is the hardcoded number we wish to use as a multiplier, in this case 10.
Within the function, the returned value from the baseNumber()
method is assigned to y
for use in the equation, but as this included function is run, it overwrites the value of the hardcoded x
variable with its own x
value. This, in turn, is passed into the equation, which throws off the expected results.
In the previous example, the x
value in both functions is public, meaning that it can be altered or overwritten by any included functions, or if in a CFC, any defined method within the component. They are, in essence, set as 'open' variables that can be accessed and amended.
By running the two functions in this way, with openly accessible variables, it has the effect of ruining our ten times table. Imagine that we had a method controlling the shopping cart in an e-commerce application, updating quantities and costs, perhaps even stock levels of products. If we left these public variables open, they could be accessed by any included functions, and the values could change dramatically altering our shopping cart and its data.
To avoid this issue, the best practice is to set any local function variables to only be accessed by that particular function. This is achieved by using the Var
keyword when setting variables. By applying variable to the Var
scope, you are restricting public access to them and declaring that they are only accessible within the method in which they are defined. This removes any chance that external functions will corrupt the values.
Note
You should always use the Var
keyword on variables that are used only inside of the function in which they are declared.
Let's alter our code to include the Var
keyword to ensure the variables are available only to the functions in which they are written:
Listing 1.17 Var scoping our variables
If we save the code with the Var
keyword applied to the variables and view the page in the browser, you will now see the correct results displayed:
Regardless of the type of variable you are using within your component methods, (a query, string, integer, array, or structure) if it is used only within the function in which it is declared, it needs to be Var
scoped to protect it and to avoid any unwanted amendments by other functions.
Placing your Var scoped variables
Up to ColdFusion 8, all Var
scoped variables were required to be placed after any arguments within the function (if there are any included), and before any CFML.
Enhancements in ColdFusion 9 removed this restriction, and Var
scoped variables can be placed anywhere within a code block or function.
Naming your Var scoped variables
While there are no strict conventions when naming your Var
scoped variables, be aware that a naming conflict will arise if your local variable name is the same as any defined argument name (or the name of another local variable).
Listing 1.18 baseNumber
function
For example, if we have written the baseNumber()
method as in the previous code, with the argument and local variable both called x
, this would display an error, as a local variable within a function cannot be declared twice.