7

For example I want to be able to programatically hit a line of code like the following where the function name is dynamically assigned without using Evaluate(). The code below of course doesn't work but represents what I would like to do.

application.obj[funcName](argumentCollection=params)

The only way I can find to call a function dynamically is by using cfinvoke, but as far as I can tell that instantiates the related cfc/function on the fly and can't use a previously instantiated cfc.

Thanks

James A Mohler
  • 11,060
  • 15
  • 46
  • 72
Dan Roberts
  • 4,664
  • 3
  • 34
  • 43

4 Answers4

9

According to the docs, you can do something like this:

<!--- Create the component instance. --->
<cfobject component="tellTime2" name="tellTimeObj">
<!--- Invoke the methods. --->
<cfinvoke component="#tellTimeObj#" method="getLocalTime" returnvariable="localTime">
<cfinvoke component="#tellTimeObj#" method="getUTCTime" returnvariable="UTCTime">

You should be able to simply call it with method="#myMethod#" to dynamically call a particular function.

Ben Doom
  • 7,865
  • 1
  • 27
  • 30
4

You can use cfinvoke. You don't have to specify a component.

<cfinvoke method="application.#funcName#" argumentCollection="#params#">
Patrick McElhaney
  • 57,901
  • 40
  • 134
  • 167
1

You can also do something very similar, to the way you wanted to use it. You can access the method within the object using the syntax you used, you just can't call it at the same time. However, if you assign it to a temp variable, you can then call it

<!--- get the component (has methods 'sayHi' and a method 'sayHello') --->
<cfset myObj = createObject("component", "test_object")>

<!--- set the function that we want dynamically then call it (it's a two step process) --->
<cfset func = "sayHi">
<cfset funcInstance = myObj[func]>
<cfoutput>#funcInstance("Dave")#</cfoutput>

<cfset func = "sayHello">
<cfset funcInstance = myObj[func]>
<cfoutput>#funcInstance("Dave")#</cfoutput>
Nick Harvey
  • 96
  • 1
  • 3
  • Copying the function from myObj into the page, or, another CFC may have a negative impact if the function uses 'this' or 'variables' scope variables. – Aaron Greenlee Oct 18 '11 at 10:43
1

In CFML, functions are first-class members of the language. This allows us to pass them around like a variable. In the following example I will copy the function named 'foobar' and rename it "$fn" within the same object. Then, we can simply call $fn().

funcName = 'foobar';    
application.obj.$fn = application.obj[funcName];
application.obj.$fn(argumentCollection=arguments);

The context of the function is important, especially if it references any values in the 'variables' or 'this' scope of the object. Note: this is not thread safe for CFC instances in shared scopes!

The fastest method is to use Ben Doom's recommendation. I just wanted to be thorough.

Community
  • 1
  • 1
Aaron Greenlee
  • 4,587
  • 4
  • 26
  • 37
  • that's a good point Aaron. Yes, if you need to maintain the context (which you generally would in any true OO style) then copying the function out of the scope of the component will fail. – Nick Harvey Oct 19 '11 at 05:07
  • As the conversation shifted to twitter, @seancorfield pointed out this won't be thread save on a singleton. If multiple threads could call the same $fn your best randomizing the name. BTW This method seems to be as fast as eval("application.obj.#funcName#(argumentCollection=arguments)"); – Aaron Greenlee Oct 20 '11 at 02:47