 |
|
|
Download
(2K) the sample code for this tutorial.
See listing1.cfm
in the sample code: |
|
Listing 1
<cfscript>
function helloWorld() {
var greeting = "Hello World!";
return greeting;
}
</cfscript>
<cfoutput>#helloWorld()#</cfoutput>
|
|
All UDFs in ColdFusion 5 must be written in CFScript, so your
code example must begin with the cfscript
tag. Begin the UDF declaration with the "function"
keyword. This is followed by the name of the UDF—in this
case, helloWorld. Next comes a set of parentheses. If your UDF
accepts any arguments, you enumerate them here. Like an "if"
statement, the body of your UDF appears within the set of curly
brackets. The body of my UDF above only contains two lines. The
first line uses the "var" keyword to declare a local
variable, called greeting.
This variable is simply set to the string "Hello World!".
Next, you use the "return" keyword to return the string.
Essentially all I did above was create a string (the welcome message)
and return it to the caller.
After creating a UDF, you call it just like any
other built-in function. (Some developers refer to a built-in
function as a "BIF" or a "normal function"
that is part of the ColdFusion server.) You simply take the name
of your UDF and surround it with cfoutput
tags and pound (#) signs. In the case above, this calls
my UDF and displays the "Hello World!" message onscreen
when run in the browser.
There are a few salient points about UDFs in
ColdFusion 5 that I want to point out. First, as I stated above,
you must use CFScript to write UDFs in ColdFusion 5. While CFScript
has a good syntax, especially if you are used to scripting languages,
for those ColdFusion developers who don't feel comfortable with
this type of coding environment, it may be a bit hard to work
with CFScript.
Secondly, CFScript can only contain expressions,
conditionals and functions. In other words, you can only do things
like this:
|
x = 2;
y = x+2;
z = len("This is a string");
if(x gte 1) {
writeOutput("Hello");
}
|
|
You can't call ColdFusion tags from CFScript. This means you can't
perform a database call, use CFHTTP, or any other ColdFusion tag.
Of course, this also means you can't do these kinds of operations
with UDFs. (There are workarounds,
like using Java or COM objects, but they aren't nearly as easy
to use as the native ColdFusion tag equivalents.) It would certainly
be nice if ColdFusion MX offered you an alternative! It just so
happens that it does.
Writing UDFs in ColdFusion MX
As I said earlier, writing UDFs in ColdFusion MX is much easier
than it is in ColdFusion 5. The cffunction
tag allows you to write your UDFs using tag syntax. Before
getting into the details of the tag, let's just take a quick look
at a sample UDF. Listing 2 shows the code from Listing 1 rewritten
using tag syntax.
|
|
See listing2.cfm
in the sample code:
|
<cffunction name="helloWorld">
<cfset greeting = "Hello World!">
<cfreturn greeting>
</cffunction>
<cfoutput>#helloWorld()#</cfoutput>
|
|
Even though the above code sample contains two tags you've never
seen before, you can probably take guess how they work. The new
cffunction tag defines a function. You
have a beginning and closing tag that wraps the body of the UDF.
The cfreturn tag returns a value. (Rocket
science, right?) Once you have declared the UDF with your cffunction tags, you can call it like
any "old style" UDF.
Listing 3 shows you a slightly more advanced
UDF.
|
|
See listing3.cfm
in the sample code:
|
<cffunction name="httpGet">
<cfargument name="urlToGet">
<cfhttp url="#urlToGet#">
<cfreturn cfhttp.filecontent>
</cffunction>
<cfset macromedia = httpGet("http://www.macromedia.com")>
<cfoutput>#htmlCodeFormat(macromedia)#</cfoutput>
|
|
This UDF, called httpGet, performs an HTTP GET on a URL. Pass
it any URL and it retrieves the source of the web page found at
that location. All I've done is simply wrap up a call to the cfhttp
tag, but as you can see I've made it easier to use,
as well as making it possible to use the cfhttp
tag from CFScript if I choose to. I also introduced another new
tag in this listing, called the cfargument tag, which lets you define
what arguments a UDF will take. The cfargument
tag takes various attributes. You can specify what the type should
be by using the type attribute.
You can also specify whether the argument is required or not.
One nice thing about UDFs written with the cffunction tag compared to CFScript is
that required and optional arguments are much easier to work with.
Let's look at another comparison. Listing 4 shows a simple UDF
that uses both required and optional arguments.
|
|
See
listing4.cfm in
the sample code:
|
<cfscript>
function highLight(str,word) {
var front = "<span style=""background-color: yellow;"">";
var back = "</span>";
var matchCase = false;
if(ArrayLen(arguments) GTE 3) front = arguments[3];
if(ArrayLen(arguments) GTE 4) back = arguments[4];
if(ArrayLen(arguments) GTE 5) matchCase = arguments[5];
if(NOT matchCase) return REReplaceNoCase(str,"(#word#)" ,"#front#\1#back#","ALL");
else return REReplace(str,"(#word#)","#front#\1#back#","ALL");
}
</CFSCRIPT>
<cfsavecontent variable="test">
This is a test string. If it contained important information,
I'd have to make sure I use the highlight function. As it stands,
the information is rather trivial.
</cfsavecontent>
<cfoutput>#highLight(test,"information")#</cfoutput>
|
This UDF takes a string and applies a highlight to matching words.
For example, if you were displaying text that resulted from a search,
you might want to use this UDF to highlight the words the user searched
for. Notice that that UDF only declares two arguments, str and
word. These are the required arguments. For the optional
arguments, you must check the length of the Arguments array. This
UDF takes three optional arguments, so it performs three different
checks. All in all, there are six lines of code to handle processing
of the arguments. At first glance, you may not realize that this
UDF takes a total of five arguments. Because it's not obvious, that's
one reason to use UDFDoc formatting. |
|
For more information on UDFs and UDFDoc, check out the ColdFusion
Common Function Library Project (CFLib.org),
which contains libraries of UDFs for ColdFusion 5. For this article,
I have removed the UDFDoc header for the sake of brevity. They
aren't required, except for documentation purposes.
Let's take a look at this same UDF written in
the cffunction tag, as shown in Listing 5.
I think the differences, and the ease of reading, will be quick
to see.
|
|
See listing5.cfm
in the sample code:
|
<cffunction name="highLight" returnType="string">
<cfargument name="str" type="string" required="true">
<cfargument name="word" type="string" required="true">
<cfargument name="front" type="string"
required="false" default="<span style=""
background-color: yellow;"">">
<cfargument name="back" type="string" required="false" default="</span>">
<cfargument name="matchCase" type="boolean" required="false" default="false">
<cfif not MatchCase>
<cfreturn REReplaceNoCase(str,"(#word#)","#front#\1#back#","ALL")>
<cfelse>
<cfreturn REReplace(str,"(#word#)","#front#\1#back#","ALL")>
</cfif>
</cffunction>
<cfsavecontent variable="test">
This is a test string. If it contained important information,
I'd have to make sure I use the highlight function. As it stands,
the information is rather trivial.
</cfsavecontent>
<cfoutput>#highLight(test,"information")#</cfoutput>
|
|
I used a few new attributes here. First, I specified a returnType
in the cffunction
tag. This ensures that the function returns the correct type of
data. I also added a type attribute
to all of the attributes. Notice that the third, fourth and fifth
cfargument tags all show required="false" as well as
default values.
Imagine a coworker who has to work with your
UDF. Now imagine them looking at this version compared to the
earlier one. It's much easier to see not only what the function returns, but
what arguments are required and what type of values they should
be. So now we have multiple reasons to use cffunction
syntax for our UDFs! As an extra bonus, you will see a nicely
formatted description of the UDF if you do this:
<cfdump
var="#highLight#">
Below is a screen shot of the highLight UDF being
CFDUMPed:
|
|
|
To be honest, I've only scratched the surface of what these new
tags can do. Download ColdFusion MX and play around with it yourself.
If you want to see examples of UDFs in action, check out the ColdFusion
Common Function Library Project http://www.cflib.org.
This is a site I maintain along with fellow Team Macromedia member
Rob Brooks-Bilson, who wrote Programming ColdFusion (O'Reilly
& Associates, 2001). We currently have over 400 UDFs that
are open-source and free for anyone to use. We also have UDFs
that work specifically under ColdFusion MX. If you create any
MX UDFs (or any UDFs for that matter), be sure to submit them
so that we can share them with the world.
|
|
|
About the author
Raymond Camden is a senior software engineer
for Mindseye,
Inc. A long time ColdFusion user, Raymond
is a co-author of the Mastering ColdFusion
series published by Sybex Inc, as well as the
ColdFusion MX Developer's Handbook. He
also presents at numerous conferences and contributes
to online webzines. He is a contributor and technical
editor of the ColdFusion Developer's Journal.
He and Rob Brooks-Bilson created and run the Common
Function Library Project, an open source repository
of ColdFusion UDFs. You can reach him at ray@camdenfamily.com.
|
| |
|
|
|