How to call a function dynamically that is part of an instantiated cfc, without using Evaluate()?
Asked Answered
R

4

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

Ridglee answered 17/9, 2008 at 15:26 Comment(2)
Just to complete the picture, Railo 3.3 actually supports your desired syntax. And I like it.Italia
You can vote for Adobe to support this syntax in CF here: Bug 82579Catlaina
L
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.

Lapith answered 17/9, 2008 at 16:3 Comment(2)
I tried various combinations for cfinvoke but somehow overlooked this. ThanksRidglee
:) nice. I didn't know you could do this, but that's way handy.Conto
R
4

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

<cfinvoke method="application.#funcName#" argumentCollection="#params#">
Roller answered 17/9, 2008 at 16:3 Comment(0)
J
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>
Jer answered 18/10, 2011 at 3:42 Comment(1)
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.Pocket
P
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.

Pocket answered 18/10, 2011 at 10:41 Comment(2)
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.Jer
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)");Pocket

© 2022 - 2024 — McMap. All rights reserved.