Posted in ColdFusion | Posted on 04-05-2006 | 12,462 views
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:
1<cfset foo = createObject("component", "president").init(42)>
But the same could be done with cfinvoke.
1<cfinvoke component="president" method="init" id="42" returnVariable="foo">
I think you will find it comes down to a style issue.


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.
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
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.
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"
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?
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?
<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.
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.
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?
<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.
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).
<cfinvoke component="#foo#" ...>
will work with a CFC already created.
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.
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. 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.
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
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
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 :)
Read an article the other day on how objects get instantiated in ColdFusion, and it was said that each method maps to an object when actually complied.
That said will it be safe to assume that Using cfinvoke to access a method on a CFC would be faster than actually creating an instance then accessing the method.
Assuming the CFC is of a services type & doesn't need any properties
[Add Comment] [Subscribe to Comments]