Ask a Jedi: cfinvoke and createObject

Gary sent in a question I've dealt with in the past, but I hear it brought up multiple times so I thought I'd share my response here. First, Gary's question:

Simply asked, given the two examples below, how are these two methods different and what are the pros and cons of each. I'm leaning towards 'why is the creatobj method preferred?' This all goes to having a better understanding of OOP.

<cfset application.blog = createObject("component","org.camden.blog.blog").init(blogname)>

<cfinvoke component="org.camden.blog.blog" method="init" returnvariable="application.blog">
<cfinvokeargument name="name" value="#blogname#">
</cfinvoke>

There are few different ways to answer this. First off - the result of both these code blocks is the exact same. They both call the init method on a CFC named blog, pass in a variable, and assign the result to a variable named application.blog. So if you consider the results - they are the same.

Technically of course they are different. One uses createObject and one uses cfinvoke. Under the hood, I'd be willing to bet they compile down to pretty much the same code.

So which is better?

The createObject method is typically what is used by most developers. I'm not sure I'd call it a "standard" but I think you would see that in code more often than the cfinvoke version.

The cfinvoke method has the benefit of working on hosts, like GoDaddy, that block access to createObject.

What do I do? When creating an instance of an object using the init method, I'll always use createObject. When calling a method on a CFC, I'll use simple script format (foo = mycfc.goo()) unless my arguments have complete logic in them. If they do - I'll use cfinvoke since you can conditionally include arguments. Here is an example:

<cfinvoke component="#application.blog#" method="goo"> <cfif hour(now()) lt 10> <cfinvokeargument name="morningmode" value="true"> </cfif> <cfinvokeargument name="name" value="dharma"> </cfinvoke>

Archived Comments

Comment 1 by todd sharp posted on 4/16/2007 at 12:51 AM

Why not just keep the conditional logic in your last example in the method itself Ray?

Aren't there also edge cases where createObject won't work - you've mentioned those before I swear (I think it was in one of the Friday puzzlers?)

Comment 2 by Raymond Camden posted on 4/16/2007 at 1:29 AM

Todd: I don't think that applies. I mean - I can see cases where such things can be either inside or out depending on business logic.

As to your second point - I'm not sure what you mean.

Comment 3 by Gary Funk posted on 4/16/2007 at 2:13 AM

I asked this question to get a better insight into CF and OOP, after reading Excellent article on running BlogCFC without CreateObject (http://www.blogcfc.com/inde... over at blogcfc.com. Scott Pinkston modified blogCFC to run without using CreateObject.

So now I'm reading about createObject and I find the entry dated April 5, 2006, Ask a Jedi: cfinvoke versus createObject (http://ray.camdenfamily.com... and the fifth comment mentions that someone changed BlogCFC so it could work on a host that does not allow createObject().

And of course even more information on cfinvoke vs createObject. And now to my point. I always read Ray's and Sean's blog on a daily basis because at any given point they have the answers to most of the asked questions. Together, these two blogs have such a wealth of information from themselves and the hundreds of other programmers that leave comments.

To Ray and Sean and the entire CF community, I say Thank You. The time you spend on your respective blogs is well spent.

Comment 4 by todd sharp posted on 4/16/2007 at 2:14 AM

Nevermind - I think I was confused :)

Comment 5 by Raymond Camden posted on 4/16/2007 at 4:55 AM

Gary, I'm not so sure your question has anything at all to do with OO principals. It is more syntax.

Comment 6 by Gary Funk posted on 4/16/2007 at 5:59 AM

Ahhhhhh... he says as another l.e.d. goes on.

Comment 7 by Sam Clement posted on 4/16/2007 at 7:33 AM

Isn't it also possible to call dynamic methods with CFINVOKE? I don't think you can do that with createObject.

Comment 8 by Tom K posted on 4/16/2007 at 12:45 PM

But from what you're saying, neither is intrinsically "faster" than the other?

Comment 9 by Raymond Camden posted on 4/16/2007 at 2:15 PM

Tom: Right. As far as I know.

Comment 10 by Raymond Camden posted on 4/16/2007 at 2:21 PM

Sam -yes - you can d dynamic methods with cfinvoke. You can't do that with ob.foo() syntax unless you use evaluate.

Comment 11 by Adam Cameron posted on 4/16/2007 at 5:11 PM

<!--- c.cfc --->
<cfcomponent>
<cffunction name="f">
<cfreturn "first one">
</cffunction>

<cffunction name="g">
<cfreturn "second one">
</cffunction>
</cfcomponent>

<!--- caller.cfm --->
<cfset o = createObject("component", "c")>

<cfset dynamicMethod = o["f"]>
<cfoutput>#dynamicMethod()#<br /></cfoutput>

<cfset dynamicMethod = o["g"]>
<cfoutput>#dynamicMethod()#<br /></cfoutput>

Comment 12 by Raymond Camden posted on 4/16/2007 at 5:45 PM

Ah, good example Adam!

Comment 13 by Rahul posted on 4/16/2007 at 8:15 PM

I would basically use createObject() in case I need to work on an object more than once.

eg

<cfscript>

user = createObject("component","cfc.user");
user.setFName("Rahul");
user.setLName("Narula");
user.age("31");

</cfscript>

Quickly we can see that all operations are done on single object.
Also the object ref is easier using this approach.

Comment 14 by Tony G. posted on 4/16/2007 at 8:27 PM

Sorry -- I don't get Adam's example (kinda dense here)

Comment 15 by Raymond Camden posted on 4/16/2007 at 10:11 PM

Tony, functions can act like variables. They are really just a type of data. So what he did was create a pointer to one using bracket notation. Then you can invoke the method via the pointer.

Comment 16 by Tony G. posted on 4/17/2007 at 4:10 AM

Thanks, Ray. I got it now. Cool trick!

Comment 17 by Sam Clement posted on 4/17/2007 at 6:19 AM

Nice one, Adam. I didn't know you could do that.

Comment 18 by Chono Sora posted on 4/17/2007 at 11:32 PM

With CreateObject, arguments can still be passed based on some logic. For example:

<cfscript>
args = StructNew();
if (hasField1) args.field1 = "some text";
if (hasField2) args.field2 = "true";
myObj = CreateObject("component","cfcs.util").init(argumentCollection=args);
</cfscript>

Comment 19 by Andy Matthews posted on 4/18/2007 at 6:55 AM

Rahul...

You can still save objects for referencing later using cfinvoke:
<cfinvoke component="basecamp" method="init" returnvariable="APPLICATION.cfc.basecamp">
<cfinvokeargument name="basecampdomain" value="http://gaylordhotels.projec...">
<cfinvokeargument name="username" value="ioweray>
<cfinvokeargument name="password" value="awishlistitem>
</cfinvoke>

then:
<cfscript>
myvar = APPLICATION.cfc.basecamp.someMethod();
</cfscript>

Comment 20 by Ahmed El-Rasheedy posted on 6/29/2007 at 7:21 PM

I think the issue here is that some developers do not create an init() method for the CFC. This would lead them to use the methods in the CFC as a UDF basically, mostly using the <cfinvoke ..>. This is not saying that you cannot do that using the createObject("","").methodName() but it is less likely.
Creating the object and keeping it to reuse it for different methods in different sections of the application (if scoped) would definitely save the instantiation and initlalization time.

Comment 21 by Mike Causer posted on 9/14/2011 at 8:28 AM

In cf9 cfscript we can go:
var mycfc = new "dynamic.path.to.cfc"()

It sucks that we cant:
mycfc."dynamicMethodName"()
or even:
mycfc[dynamicMethodNameVariable]()

Comment 22 by Raymond Camden posted on 9/14/2011 at 2:55 PM

You can do so now with evaluate().
As to what you demonstrated as an alternative....

Wait.

:)