So I could have sworn I had blogged on this before, but I couldn't find it in my archives, so here goes. (And if I do start repeating myself, let me know folks!)
Is there a reason to favor cfinvoke over cfobject? Does cfinvoke clean up after itself faster?
Technically you are comparing apples and oranges. The cfobject tag (and createObject function) are meant to create an instance of a CFC. The cfinvoke tag runs a method on a CFC. You can use createObject to both create a CFC and run a method:
But the same could be done with cfinvoke.
I think you will find it comes down to a style issue.


Comment 1 written by Christopher Wigginton on 5 April 2006, at 5:05 PM
Comment 2 written by Ryan Guill on 5 April 2006, at 5:22 PM
cfargument name="myargumentname" value="myargument" /
/cfinvoke
sorry if that makes it hard to read, i left out the greater than less than signs so it wouldnt get stripped.
Comment 3 written by John Elkins on 5 April 2006, at 5:40 PM
In addition, by instantiating an object and then calling the objects methods it creates less load on server for garbage collection. If a site that has a lot of traffic instantiates an object in the application scope (only do this for objects that do not need to maintain instance "state" data).. its a lot less work for the server than constantly invoking arguments over and over again.
My $.02
Comment 4 written by Raymond Camden on 5 April 2006, at 9:37 PM
Comment 5 written by MrBuzzy on 6 April 2006, at 5:18 AM
If you're writing your CF for portability (on to cheap hosting solutions for example) then this is a reason to use cfinvoke only.
Perhaps there should be a createComponent() function. So it can be differentiated from the java stuff in the Sandbox.
Comment 6 written by john s. on 6 April 2006, at 8:28 AM
I think that would help clear the water a bit more and give some of us a refresh.
@Ryan, I'm not sure I follow your stateless example in regards to initilization code and local code having to be run if you use cfinvoke.
I think I'm confused on the "instance state"
Comment 7 written by Ryan Guill on 6 April 2006, at 8:36 AM
When you set variables local to an object and create an object out of it, it is said to have state. When you just call a component directly through cfinvoke, without first creating an object out of it, it is said to be stateless, meaning it has no "instance" variables.
Generally, stateless is fine for "services", or components that do not need to "know" anything, they just take arguments and do something with them. But if you want your component to know something, that is, you tell it once and it remembers it, then you are going to have to create an object out of it.
For example, to make my code portable between our development and production environments, I always pass in the datasource that an object should use when I create it, and then for the rest of my app where I am using that object, I dont have to pass in the datasource any more.
Does that make more sense or is it still clear as mud?
Comment 8 written by Ryan Guill on 6 April 2006, at 8:39 AM
Comment 9 written by Michael White on 6 April 2006, at 9:12 AM
Comment 10 written by Phillip Senn on 6 April 2006, at 10:38 AM
Here's what I do:
<cfset xxxObj = CreateObject("Component","Components.xxx").Init("myDataSource")>
<cfset xxxQry = xxxObj.View1()>
<cfdump var="#xxxQry#">
xxx.cfc contains:
<cfcomponent displayname="xxx" output="False">
<cffunction name="Init" output="true" returntype="components.xxx">
<cfargument name="DSN" required="yes">
<cfset Variables.DSN = arguments.DSN>
<cfreturn this>
</cffunction>
<cffunction name="View1" output="False" returntype="query" hint="I return everything from xxxView">
<cfargument name="xxxID" type="numeric" required="no">
<cfset var rst = "">
<cfquery name="rst" datasource="#Variables.DSN#">
SELECT * FROM xxx
<cfif isDefined("arguments.xxxID") and isValid("integer",arguments.xxxID)>
WHERE xxxID = #arguments.xxxID#
</cfif>
</cfquery>
<cfreturn rst>
</cffunction>
</cfcomponent>
The thinking is:
ANYTHING THAT HAS TO DO WITH TABLE xxx GOES THROUGH THIS CFC.
So my question is:
How would you rewrite line 2:
<cfset xxxQry = xxxObj.View1()>
using cfinvoke?
Comment 11 written by Ryan Guill on 6 April 2006, at 10:42 AM
<cfinvoke component="components.xxx" method="View1" returnvariable="xxxQry">
<cfinvokeargument name="dsn" value="myDatasource" />
</cfinvoke>
But this illustrates the point that if you have many methods in your component that all need the same dsn, why not create and object out of it while passing in the dsn, and then use it throughout your component.
While both methods may be <em>functionally the same</em> they are quite different.
Comment 12 written by Phillip Senn on 6 April 2006, at 10:51 AM
For the sake of simplicity, I left out the following functions in xxx.cfc:
<cffunction name="View2" output="False" returntype="query" hint="I return a list starting from xxxID">
</cffunction>
<cffunction name="NextRecord" returntype="numeric" output="false" hint="I return the next xxxID">
</cffunction>
<cffunction name="PrevRecord" output="False" returntype="numeric" hint="I return the Prev xxxID">
</cffunction>
The idea is that you don't have any cfquery commands in your programs. If you need something from table xxx, you have to create a function and either return a query or return a primary key ID.
Comment 13 written by Drew on 17 April 2006, at 7:51 AM
You mentioned earlier on that I can call cfinvoke on an object that's already in existance. This would mean that I can now pass named values to functionS rather than relying on position as I normally would?
Could that lend itself to the thought that because the arguments are named the function call would be quicker, as well as more flexible?
Comment 14 written by Ryan Guill on 17 April 2006, at 7:59 AM
<cffunction name="myFunct">
<cfargument name="one" required="True" />
<cfargument name="two" required="true" />
</cffunction>
I can call that function like this:
<cfset myFunct(two=a,one=b) />
Which gives you named parameters. This way of doing things can also be used for providing values for non-required arguments.
Also, you can pass argument collections into functions, which is also passing them in named as well in a sense. For the function above I could call it like so:
<cfset myArgs = structNew() />
<cfset myArgs.two = a />
<cfset myArgs.one = b />
<cfset myFunct(argumentCollection=myArgs) />
Now, I much prefer the cfinvoke syntax because I believe it to be easier to read, even though it is a little more typing.
As far as speed, I doubt the difference in any of these methods really make much difference. Named or not, the functions would probably run about the same. To me, no matter which one ran faster though, the readability that named parameters gives you is worth it.
But try all the different methods and time them to see what you get, if you are really worried about performance. But to me, ease of maintenance is my first priority.
Comment 15 written by Henry Ho on 23 February 2009, at 1:26 PM
Doesn't CFINVOKE create an instance of the component before invoking the method anyway? I believe it does, and therefore I do not think CFINVOKE has any performance advantage over CreateObject()
e.g.
<!-- x.cfc -->
<cfcomponent>
<cfscript>
variables.x = 123; // sudo-contructor init
function getX(){
return variables.x;
}
</cfscript>
</cfcomponent>
<!-- getX.cfm -->
<cfset x = createObject("component","x").getX()
<!--- should be the same as --->
<cfinvoke component="x" method="getX" returnvariable="x">
Notice that if cfinvoke is really just invoking the method getX, it should not have been able to get x, since x belongs to the Variables scope (a scope that's created once the component has been instantiated).
Comment 16 written by Raymond Camden on 23 February 2009, at 1:31 PM
<cfinvoke component="#foo#" ...>
will work with a CFC already created.
Comment 17 written by Henry Ho on 23 February 2009, at 1:40 PM
Although there's no 'static' class in CF, but like when you have a helper method that get called throughout many objects, but you don't want to use <cfinclude> to inject that method. Then, in that case, use of createObject() then invoke should be same as cfinvoke that method directly.
Comment 18 written by Raymond Camden on 23 February 2009, at 1:53 PM
Comment 19 written by Susan Brun on 18 May 2010, at 10:52 AM
What if you have two applications that want to be able to use the same CFC, can one application create the object, and the other application use the object?
Comment 20 written by Raymond Camden on 18 May 2010, at 10:54 AM
Yes. If thats what you want.
"What if you have two applications that want to be able to use the same CFC, can one application create the object, and the other application use the object?"
Yes - but you need to modify how you do things. The best way to handle this is with ColdSpring: http://www.coldspringframework.org/
It can manage creating singletons for you.
Comment 21 written by Khurram on 27 May 2010, at 4:31 PM
Pretty obvious that I could change all the stuff where I found the createObject as follows
<cfset xxx = CreateObject("component","cfc.xxx").init("requiredparam") />
simply to the cfinvoke with the method attribute and cfinvokearguments within it.
But what if I have to change the following statement to the cfinvoke with no calling method. what would you recommend to do..
<cfset obj_xxx = CreateObject("component","cfc.xxx") />
If you noticed the above statement initiating the component but is not calling the init method (which actually does have one required parameter as below)
<cfcomponent displayname="xxx" output="false">
<cffunction name="init" access="public" returntype="xxx" output="false">
<cfargument name="required_param" type="cfc.xxx2" required="true" />
<!--- other work --->
<cfreturn this />
</cffunction>
</cfcomponent>
Above context works great but with CreateObject as it just returns the instance of the component and I can use it later on the page.
I am just not able to figure it out how can I use <cfinvoke> to get instance of the component as I don't have any parameter of type "xxx2" to send in to the init method.
Hope I tried good to reproduce the problem.
Regards
Khurram
Comment 22 written by Raymond Camden on 28 May 2010, at 1:14 AM
Comment 23 written by Khurram on 28 May 2010, at 8:04 AM
I actually don't require to use the init method at all. It was a case what I felt being trouble and the I just managed to prepare a required parameter to send in. But right after that I thought of making the new method just as you told above. I did it as below..
<cffunction name="doNothingButReturnThis" access="public" returntype="xxx" output="false">
<cfreturn this />
</cffunction>
So would it be perfectly equal to the CreateObject (without init method) using cfinvoke with this above method
Comment 24 written by Raymond Camden on 28 May 2010, at 10:10 AM
Comment 25 written by Khurram on 28 May 2010, at 10:15 AM
And I was just not sure what I did is would be the same as createObject in the listed scenario. So I had to ask this question to be sure.
So thanks alot. now after your "Yes" I am sure that I can have it like that :)
[Add Comment] [Subscribe to Comments]