User-Defined Functions in <cfscript>
To create a custom function using <cfscript>, you declare your function just as you would in JavaScript, using the function keyword. Like JavaScript, UDFs can accept and return values and can be embedded within other functions. And because UDFs support recursion, you can call each function from within the function itself. (User-defined functions can be created using <cffunction>, as well.)
Listing 44.12 shows an example of a <cfscript>-based UDF named TitleCase() that takes a string as its one argument and returns the string converted to title case (with the first letter of each word capitalized, and the rest in lowercase). TitleCase() can be called like any other function, as shown in the listing.
Listing 44.12. UserDefinedFunction.cfm—Creating and Calling a UDF
<!--- Author: Adam Phillip Churvis -- ProductivityEnhancement.com ---> <!--- Script-based user defined function (UDF) ---> <cfscript> function TitleCase(rawSentence) { var titleCaseSentence = ""; var numberOfListElements = ListLen(rawSentence, ", .;-:"); var currentElement = ""; var currentWord = ""; for(i=1; i <= numberOfListElements; i++) { currentElement = ListGetAt(rawSentence, i, ", .;-:"); currentWord = UCase(Left(currentElement, 1)); if(Len(currentElement) > 1) { currentWord = currentWord & LCase(Right(currentElement, Len(currentElement) - 1)); } titleCaseSentence = titleCaseSentence & " " & currentWord; } titleCaseSentence = Trim(titleCaseSentence) & "."; return titleCaseSentence; } </cfscript> <cfoutput> #TitleCase("i AM the very moDEL of a MODERN major general.")# </cfoutput>
Where to Define UDFs
You can define UDFs in two places: in the same ColdFusion template where the function is called, or in a separate .cfm file that is included in the same ColdFusion template where the function is called. You can also assign them into shared variable scopes to permit reuse across multiple requests, or place them into a CFC (an instance of which itself could be assigned to a shared variable scope). Which technique should you use? It depends on how and where the function will be used.
If the user-defined function is used only in a single ColdFusion template, you can define the function directly in that template, typically at the top of the page. But since UDFs are built for reuse, you’ll most likely have occasion to call the same UDFs from multiple templates. In that case, you could define your UDF in an external .cfm file and then <cfinclude> that file in the ColdFusion templates that call the UDF.
But what if your application uses many different UDFs? To accommodate this, you could categorize your UDFs by the type of function they perform and then group them together in .cfm files that are named for each type of function. For example, if you have three functions that manipulate strings and seven functions that handle mathematical calculations, you might create two files named StringFunctions.cfm and MathFunctions.cfm and place the function definitions in these two files. Then, whenever a ColdFusion template needs to call a math function, you would simply <cfinclude> the MathFunctions.cfm in that template and then call the function wherever it was needed.
That approach was our only option prior to ColdFusion MX 6, but with the advent of CFCs, it may be better to place such highly reused user-defined functions in a CFC instead. In fact, you may be surprised to learn that you can place a script-based UDF into a CFC and call it just like any other CFC method. Clearly though, <cffunction>-based UDFs offer a great deal more power, with definable arguments, return types, ability to make them remote, etc. See Chapter 24, “Building User-Defined Functions,” in ColdFusion 8 Web Application Construction Kit, Volume 2: Application Development,” for more details. While you may want to convert such script-based UDFs to use <cffunction> instead when inside a CFC, note that you could leave the bulk of the UDF within <cfscript> inside the <cffunction>, removing only the opening/closing function declaration block.
Finally, just as CFC instances can be placed into shared variable scopes for reuse across multiple requests, note as well that user-defined functions (defined outside a CFC, whether with <cfscript> or <cffunction>) can also be placed into shared variable scopes. This is beyond the scope of this chapter to detail, but just know that you can assign a function to a variable just like any other assignment and can then refer to the function as being within that scope just as you would a scope-based variable.
There are a few things you should keep in mind about user-defined functions:
- The UDF name cannot match a built-in function name and cannot start with cf.
- The number of arguments passed in the function call must be greater than or equal to the number of arguments declared in the script-based function definition.
- The var keyword initializes variables local to the function. All variables created inside a user-defined function should be declared as local function variables using the var keyword. You must declare all local function variables immediately after the function is declared and before any logic is executed. Arguments are already local to the function that defines them, so you don’t need to separately declare them in the body of the function.
No discussion of user-defined functions would be complete without referring you to cflib.org, a Web site that contains hundreds of useful UDFs and libraries of UDFs available for free download and use. Do yourself a favor and head over there now for a quick tour of what they offer.