You can use tags or CFScript to create a UDF. Each technique has advantages and disadvantages.
You use the function
statement to define the function in CFScript. CFScript function definitions have the following features and limitations:
The following is a CFScript definition for a function that returns a power of 2:
<cfscript>
function twoPower(exponent)
{
return 2^exponent;
}
</cfscript>
For more information on how to use CFScript to define a function, see "Defining functions in CFScript".
You use the cffunction
tag to define a UDF in CFML. The cffunction
tag syntax has the following features and limitations:
cffunction
tag provides attributes that enable you to easily limit the execution of the tag to authorized users or specify how the function can be accessed.
The following code uses the cffunction
tag to define the exponentiation function:
<cffunction name="twoPower" output=True>
<cfargument name="exponent"> <cfreturn 2^exponent> </cffunction>
For more information on how to use the cffunction
tag to define a function, see "Defining functions using the cffunction tag".
The following rules apply to functions that you define using CFScript or the cffunction
tag:
You can define a function in the following places:
cfinclude
tag. The cfinclude
tag must be executed before the function gets called. For example, you can define all your application's functions on a single page and place a cfinclude
tag at the top of pages that use the functions.For recommendations on selecting where you define functions, see the sections "Using Application.cfm and function include files" and "Specifying the scope of a function".
All function arguments exist in their own scope, the Arguments scope.
The Arguments scope exists for the life of a function call. When the function returns, the scope and its variables are destroyed.
However, destroying the Argument scope does not destroy variables, such as structures or query objects, that ColdFusion passes to the function by reference. The variables on the calling page that you use as function arguments continue to exist; if the function changes the argument value, the variable in the calling page reflects the changed value.
The Arguments scope is special, in that you can treat the scope as either an array or a structure. This dual nature of the Arguments scope is useful because it makes it easy to use arguments in any of the following circumstances:
cffunction
tag.
The following sections describe the general rules for using the Arguments scope as an array and a structure. For more information on using the Arguments scope in functions defined using CFScript, see "Using the Arguments scope in CFScript". For more information on using the Arguments scope in functions defined using the cffunction
tag, see "Using the Arguments scope in cffunction definitions".
The following rules apply to the Arguments scope and its contents:
cffunction
to define the function, the scope always contains an entry "slot" for each declared argument, even if you do not pass the argument to the function when you call it. If you do not pass a declared (optional) argument, the scope entry for that argument is empty.When you call a function that you defined using CFScript, you must pass the function a value for each argument declared in the function definition. Therefore, the Arguments scope for a CFScript call does not have empty slots.
The following example shows these rules. Assume that you have a function declared, as follows:
<cffunction name="TestFunction">
<cfargument name="Arg1" > <cfargument name="Arg2"> </cffunction>
You can call this function with a single argument, as in the following line:
<cfset TestFunction(1)>
The resulting Arguments scope looks like the following:
As an array |
As a structure |
||
---|---|---|---|
Entry |
Value |
Entry |
Value |
1 |
1 |
Arg1 |
1 |
2 |
undefined |
Arg2 |
undefined |
In this example, the following functions return the value 2 because there are two defined arguments:
ArrayLen(Arguments)
StructCount(Arguments)
However, the following tests return the value False, because the contents of the second element in the Arguments scope is undefined.
Isdefined("Arguments.Arg2") testArg2 = Arguments[2]>
Isdefined("testArg2")
Note: The IsDefined
function does not test the existence of array elements. To test whether an array index contains data, copy the array element to a simple variable and use the IsDefined
function to test the existence of the copy.
The following rules apply to referencing Arguments scope as an array:
cffunction
tag.However, using argument names in this manner is not good programming practice because you cannot ensure that you always use the same optional argument names when calling the function.
To demonstrate these rules, define a simple function that displays the contents of its Arguments array and call the function with various argument combinations, as shown in the following example:
<cffunction name="TestFunction" >
<cfargument name="Arg1"> <cfargument name="Arg2"> <cfloop index="i" from="1" to="#ArrayLen(Arguments)#"> <cfoutput>Argument #i#: #Arguments[i]#<br></cfoutput> </cfloop> </cffunction> <strong>One Unnamed argument</strong><br> <cfset TestFunction(1)> <strong>Two Unnamed arguments</strong><br> <cfset TestFunction(1, 2)> <strong>Three Unnamed arguments</strong><br> <cfset TestFunction(1, 2, 3)> <strong>Arg1:</strong><br> <cfset TestFunction(Arg1=8)> <strong>Arg2:</strong><br> <cfset TestFunction(Arg2=9)> <strong>Arg1=8, Arg2=9:</strong><br> <cfset TestFunction(Arg1=8, Arg2=9)> <strong>Arg2=6, Arg1=7</strong><br> <cfset TestFunction(Arg2=6, Arg1=7)> <strong>Arg1=8, Arg2=9, Arg3=10:</strong><br> <cfset TestFunction(Arg1=8, Arg2=9, Arg3=10)> <strong>Arg2=6, Arg3=99, Arg1=7</strong><br> <cfset TestFunction(Arg2=6, Arg3=99, Arg1=7)>
Note: Although you can use the Arguments scope as an array, the IsArray(Arguments) function always returns false and the cfdump
tag displays the scope as a structure.
The following rule applies when referencing Arguments scope as a structure:
The following rules are also true, but avoid writing code that uses them. To ensure program clarity, only use the Arguments structure for arguments that you name in the function definition. Use the Arguments scope as an array for optional arguments that you do not declare in the function definition.
Note: The IsDefined
function always returns false when you reference an unnamed optional arguments using structure notation. For example, IsDefined(Arguments.3)
for the function described in the preceding paragraph always returns false.
In addition to the Arguments scope, each function can have a number of variables that exist only inside the function, and are not saved between times the function gets called. As soon as the function exits, all the variables in this scope are removed.
In CFScript, you create function-only variables with the var
statement. Unlike other variables, you never prefix function-only variables with a scope name.
For more information on using function-only variables, see "Using function-only variables".
An argument's name should represent its use. For example, the following code is unlikely to result in confusion:
<cfscript>
function SumN(Addend1,Addend2) { return Addend1 + Addend2; } </cfscript> <cfset x = 10> <cfset y = 12> <cfoutput>#SumN(x,y)#<cfoutput>
The following, similar code is more likely to result in programming errors:
<cfscript>
function SumN(x,y) { return x + y; } </cfscript> <cfset x = 10> <cfset y = 12> <cfoutput>#SumN(x,y)#<cfoutput>
You define functions using CFScript in a manner similar to defining JavaScript functions. You can define multiple functions in a single CFScript block.
Note: For more information on using CFScript, see Chapter 6, "Extending ColdFusion Pages with CFML Scripting".
A CFScript function definition has the following syntax.
function functionName( [argName1[, argName2...]] ) { CFScript Statements }
The following table describes the function variables:
The body of the function definition must consist of one or more valid CFScript statements. The body must be in curly braces, even if it is a single statement.
The following two statements are allowed only in function definitions:
The following example function adds the two arguments and returns the result:
<cfscript>
function Sum(a,b)
{
var sum = a + b;
return sum;
}
</cfscript>
In this example, a single line declares the function variable and uses an expression to set it to the value to be returned. This function can be simplified so that it does not use a function variable, as follows:
function MySum(a,b) {Return a + b;}
You must always use curly braces around the function definition body, even if it is a single statement.
A function can have optional arguments that you do not have to specify when you call the function. To determine the number of arguments passed to the function, use the following function:
ArrayLen(Arguments)
When you define a function using CFScript, the function must use the Arguments scope to retrieve the optional arguments. For example, the following SumN function adds two or more numbers together. It requires two arguments and supports any number of additional optional arguments. You can refer to the first two, required, arguments as Arg1
and Arg2
or as Arguments[1]
and Arguments[2]
. You must refer to the third, fourth, and any additional optional arguments as Arguments[3]
, Arguments[4],
and so on.
function SumN(Arg1,Arg2)
{ var arg_count = ArrayLen(Arguments); var sum = 0; var i = 0; for( i = 1 ; i LTE arg_count; i = i + 1 ) { sum = sum + Arguments[i]; } return sum; }
With this function, any of the following function calls are valid:
SumN(Value1, Value2)
SumN(Value1, Value2, Value3) SumN(Value1, Value2, Value3, Value4)
The code never uses the Arg1 and Arg2 argument variables directly, because their values are always the first two elements in the Arguments array and it is simpler to step through the array. Specifying Arg1 and Arg2 in the function definition ensures that ColdFusion generates an error if you pass the function one or no arguments.
Note: Avoid referring to a required argument in the body of a function by both the argument name and its place in the Arguments scope array or structure, as this can be confusing and makes it easier to introduce errors.
For more information on the Arguments scope, see "About the Arguments scope".
The cffunction
and cfargument
tags let you define functions in CFML without using CFScript.
Note: This chapter describes how to use the cffunction
tag to define a function that is not part of a ColdFusion component. For information on ColdFusion components, see Chapter 11, "Building and Using ColdFusion Components". For more information on the cffunction
tag, see CFML Reference.
A cffunction
tag function definition has the following format:
<cffunction name="functionName" [returnType="type" roles="roleList"
access="accessType" output="Boolean"]>
<cfargument name="argumentName" [Type="type" required="Boolean"
default="defaultValue">] . . Function body code . . <cfreturn expression> </cffunction>
where square brackets ([]) indicate optional arguments. You can have any number of cfargument
tags.
The cffunction
tag specifies the name you use when you call the function. You can optionally specify other function characteristics, as described in the following table:
Attribute |
Description |
---|---|
name |
The function name. |
returnType |
(Optional) The type of data that the function returns. The valid standard type names are: any, array, binary, boolean, date, guid, numeric, query, string, struct, uuid, variableName and void. If you specify any other name ColdFusion requires the argument to be a ColdFusion component with that name. ColdFusion throws an error if you specify this attribute and the function tries to return data with a type that ColdFusion cannot automatically convert to the one you specified. For example, if the function returns the result of a numeric calculation, a returnType attribute of string or numeric is valid, but array is not. |
roles |
(Optional) A comma-delimited list of security roles that can invoke this method. If you omit this attribute, ColdFusion does not restrict user access to the function. If you use this attribute, the function executes only if the current user is logged in using the cfloginuser tag and is a member of one or more of the roles specified in the attribute. Otherwise, ColdFusion throws an unauthorized access exception. For more information on user security, see Chapter 16, "Securing Applications". |
output |
(Optional) Determines how ColdFusion processes displayable output in the function body. If you do not specify this option, ColdFusion treats the body of the function as normal CFML. As a result, text and the result of any cfoutput tags in the function definition body are displayed each time the function executes.If you specify True or "yes", the body of the function is processed as if it were in a cfoutput tag. ColdFusion displays variable values and expression results if you surround the variables and expressions with pound signs.If you specify False or "no" the function is processed as if it were in a cfsilent tag. The function does not display any output. The code that calls the function is responsible for displaying any function results. |
You must use cfargument
tags for required function arguments and named optional arguments. All cfargument
tags must precede any other CFML code in cffunction
tag body. Therefore, put the cfargument
tags immediately following the cffunction
opening tag. The cfargument
tag takes the following attributes:
Note: The cfargument
tag is not required for optional arguments. This feature is useful if a functions can take an indeterminate number of arguments. If you do not use the cfargument
tag for an optional argument, reference it using its position in the Arguments scope array. For more information see "Using the Arguments scope as an array".
The most important advantage of using the cffunction
tag over defining a function in CFScript is that you can include CFML tags in the function. Thus, UDFs can encapsulate activities, such as database lookups, that require ColdFusion tags. Also, you can use the cfoutput
tag to display output on the calling page with minimal coding.
The following example function looks up and returns an employee's department ID. It takes one argument, the employee ID, and looks up the corresponding department ID in the CompanyInfo Employee table:
<cffunction name="getDeptID" >
<cfargument name="empID" required="true" type="numeric">
<cfquery dataSource="CompanyInfo" name="deptID">
SELECT Dept_ID
FROM Employee
WHERE Emp_ID = #empID#
</cfquery>
<cfreturn deptID.Dept_ID>
</cffunction>
Note: The cfquery
tag automatically puts the query result in the Variables scope, so you cannot limit its result to the This scope.
When you define a function using the cffunction
tag, you generally refer to the arguments directly by name if all arguments are named in the cfargument
tags. If you do use the Arguments scope identifier, follow the rules listed in "About the Arguments scope".