The Dopefly Tech Blog

<< The Dopefly Tech Blog Main page

Calling functions with a dynamic name

posted under category: ColdFusion on May 28, 2009 at 1:00 am by MrNate

For a while now, the CF community has been stumbling around the concept of calling a dynamic function. Well, as it turns out, ColdFusion is more functional that it may seem on the surface. Let's have some fun with what, at first, seems like a difficult problem.

Let's say we have a method that receives the name of another method as an argument: myStaticFunction("myDynamicFunction"). Now what? First, here's the methods (I haven't checked any of this, so let's call it pseudo-code.

function myDynamicFunction(){return true;}

function myStaticFunction(methodName) {
methodName(); // fails for calling a string like a function
variables[methodName](); // fails for a syntax error - []() = bad cfml!
// umm, now what?
}

So here we are in the same old spot. First, the old school method, the one easily turned to in time of need, the cfinvoke tag. Personally, I dislike the cfinvoke tag. It seems to take me out of my flow. It ruins my mojo. It's like longhand syntax for CF - it's somewhat of an oxymoron. Nevertheless, here's what you would do:

<!--- First, note that we have to rewrite it in tags. Not awful, but I dislike the switch. --->
<cffunction name="myStaticFunction">
<cfargument name="methodName" />
<cfset var methodResult = "" />
<cfinvoke method="#methodName#" returnvariable="methodResult" />
<cfreturn methodResult />
</cffunction>

This works, but there's got to be a better way! There has to be a less cheap way, something without all the #'s and stuff. And there is:

// back to cfscript, yay!
function myStaticFunction(methodName) {
var method = variables[methodName];
return method();
}

That's much more like it! Of course this assumes we're in a cfc or something, where the method is in the variables scope. Now, what other magical things can we do?

Well, I wasn't going to share this one until the next entry, but since you're talking me into it, here it is with onMissingMethod, dynamically calling a method with dynamic arguments. This onMissingMethod attempts to call a getter when you just call the property - in other words, user.name() will be automatically translated into user.getName(), to give you a nice jQuery type of syntax:

function onMissingMethod(missingMethodName, missingMethodArguments) {
var f = 0;
if (structKeyExists(variables, "get" & arguments.missingMethodName)) {
f = variables["get" & arguments.missingMethodName];
f(argumentCollection=arguments.missingMethodArguments);
} else {
// choke!
}
}

Too old to comment!
On Jun 10, 2009 at 1:00 AM Dave Anderson (dave at the ever-endearing metaldog.net) said:
Did you try evaluate() ? Would something like this not work?

function myDynamicMethod() {
return true;
}
function myStaticMethod(methodName) {
return evaluate('#methodName#()');
}
writeOutput(myStaticMethod('myDynamicMethod'));

On Jun 10, 2009 at 1:00 AM Nathan Strutz (http://www.dopefly.com/) said:
Oh, how pretentious of me. You should avoid the evaluate function as much as possible, wherever possible. Evaluate is evil!

3 reasons. It promotes sloppy code, there are potential security risks, and it is slow.

Here's some resources on it:

Comments on the CF6 Docs:
http://livedocs.adobe.com/coldfusion/6/CFML_Reference/functions-pt176.htm
CF7 and 8 have a footnote about avoiding the use.
Daryl Banttari:
http://cfprimer.blogspot.com/2005/03/avoid-evaluate.html
And finally Wikipedia has a good overview and discussion on it:
http://en.wikipedia.org/wiki/Eval

On Apr 5, 2011 at 1:00 AM delijah (raffael.wannenmacher who really likes gmail.com) said:
Does not work with persistent objects getter and setter methods :(

On Apr 5, 2011 at 1:00 AM Nathan Strutz (www.dopefly.com) said:
Good call! - I was thinking of drafting a new blog entry on this, but I think Ben Nadel may beat me to it (if he hasn't already).
Too old to comment!