Book Image

Object-Oriented Programming in ColdFusion

By : Matthew Gifford
Book Image

Object-Oriented Programming in ColdFusion

By: Matthew Gifford

Overview of this book

Are you tired of procedural programming or is your extensive code base starting to become un-manageable? Breathe some new life into your code and improve your development skills with the basic concepts of object-oriented programming. Utilize objects, modular components, and design patterns to expand your skills and improve your ColdFusion applications. Packed with example code, and written in a friendly, easy-to-read style, this book is just what you need if you are serious about ColdFusion.This book is a fast-paced tutorial to important ColdFusion object-oriented programming topics. It will give you clear, concise, and practical guidance to take you from the basics of ColdFusion to the skills that will make you a ColdFusion developer to be reckoned with. Don't be put off by jargon or complex diagrams; read and see how you can benefit from this book and extend your development skills in the process.Using the practical examples within this guide, you will learn how to structure your applications and code, applying the fundamental basics of object-oriented programming to develop modular, reusable components that will scale easily with your application. You will learn the basic fundamental practices of object-oriented programming, from object creation and re-use, to Bean objects, service layers, Data Access objects, and sample design patterns to gain a better understanding of OOP using examples that can be altered and applied in your application. Complete with detailed code samples and snippets, and written in a friendly easy-to-follow style, you will be able to break free from writing purely procedural code and enhance your applications by building structured applications utilizing basic design patterns and object-oriented principles.
Table of Contents (14 chapters)
Object-Oriented Programming in ColdFusion
Credits
Foreword
About the Author
Acknowledgement
About the Reviewer
Preface

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.

<cfoutput>
<cffunction name="baseNumber" returnType="numeric">
<cfargument name="a" type="numeric" required="true" />
<cfset x = arguments.a />
<cfreturn x />
</cffunction>
<cffunction name="multiplyNumbers" returntype="string">
<cfargument name="a" type="numeric" required="true" />
<cfargument name="b" type="numeric" required="true" />
<!--- multiply our basenumber value by 10 --->
<cfset x = 10 />
<cfset y = baseNumber(a) />
<cfreturn y & " multiplied by " & x & " = " & x * arguments.b />
</cffunction>
<cfloop from="1" to="10" index="i">
#multiplyNumbers(i,i)#<br />
</cfloop>
</cfoutput>

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:

1 multiplied by 10 = 10
2 multiplied by 10 = 20

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:

<cffunction name="baseNumber" returnType="numeric">
<cfargument name="a" type="numeric" required="true" />
<cfset x = arguments.a />
<cfreturn x />
</cffunction>
<cffunction name="multiplyNumbers" returntype="string">
<cfargument name="a" type="numeric" required="true" />
<cfargument name="b" type="numeric" required="true" />
<!--- multiply our basenumber value by 10 --->
<cfset x = 10 />
<cfset y = baseNumber(a) />
<cfreturn y & " multiplied by " & x & " = " & x * arguments.b />
</cffunction>

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.

Using the Var scope

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:

<cffunction name="baseNumber" returnType="numeric">
<cfargument name="a" type="numeric" required="true" />
<cfset Var x = arguments.a />
<cfreturn x />
</cffunction>
<cffunction name="multiplyNumbers" returntype="string">
<cfargument name="a" type="numeric" required="true" />
<cfargument name="b" type="numeric" required="true" />
<cfset Var x = 10 />
<cfset var y = baseNumber(a) />
<cfreturn y & " multiplied by " & x & " = " & x * arguments.b />
</cffunction>

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).

<cffunction name="baseNumber" returnType="numeric">
<cfargument name="x" type="numeric" required="true" />
<cfset Var x = arguments.x />
<cfreturn x />
</cffunction>

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.