Posted on March 7, 2007
I was responding to “CFC interaction and persistent scopes (newbie questions)” on the
CFCDEV list and it turned into this post.
One of the many questions asked by the original poster was regarding passing one object into another. Nando posted this in reply:
“In reality, all that is passed is a reference to the object. CFAS creates a variable when you instantiate an object in memory, and when you give it some name in some scope, then it has a reference to that variable. CFCs are passed by reference.
Kelly Brown has a great post about how
There are no Pointers in Coldfusion and I’d like to expand on that.
Basically the problem is that if you write
<cfset session.foo = "Hello" /> <cfset variables.foo = session.foo /> <cfset variables.foo = "Goodbye">
then the value of
session.foo is also
Goodbye. However, if you
duplicate() the session variable, you can avoid this problem.
<cfset session.foo = "Hello" /> <cfset variables.foo = duplicate(session.foo) /> <cfset variables.foo = "Goodbye">
variables.foo = "Goodbye and
session.foo is still
We can’t use
duplicate() on objects (CFCs) yet and I’ve no idea when we ever will. This is why you have to be very careful when you’re injecting session objects into other objects.
I found we had a problem with exactly that today (the day before open beta of our new site. Joy!).
Another developer had injected a core session object into another object in order to pass along its arguments in one shot.
<cflock ...> <!--- session.data is a bean ---> <cfset request.data = session.data /> </cflock>
<cfset data = request.data /> <--- ... ---> <cfset moreData = createObject("component", "moreData").init()/> <cfset moreDataDAO = createObject("component", "moreDataObj").init( DSN = request.DSN ) /> <cfset moreData.read( moreData = moreData, data = data )/>
<cfset arguments.data.init( ... ) /> <!--- etc. --->
data and since
data already exists in session, the intent was to inject
data, then call
moreData.init(). The problem is that he called
data.init() before passing
So let’s follow the chain of references to see what happened:
session.data -> request.data -> variables.data -> arguments.data.init()
data.init() was called from inside the other object without passing in values for all the arguments of the init method. Whenever this process was run, the data bean stayed in session, but its contents were reverted to their default, empty values.
Fortunately it only took a few minutes to put a band-aid in place. A complete fix should be ready by the end of the week. I think this is an excellent example of how fragile applications can become when developers lose track of their data’s origins.
So how do you solve this problem? Instead of passing the
data bean into
moreData as a single argument, the
init() method in
moreData shoud add the arguments defined in
Adrian J. Moreno
Adrian is a CTO and solution architect specializing in software modernization. More information