Reputation: 1820
I really hope you can help me. I usually read my session variables into a local variable, so that I don't have to create endless read locks. But I came across some interesting behavior. Note that I have not applied any write locks for brevity's sake:
Consider the following:
EXAMPLE 1:
<cfset session.testvalue = 1 />
<cfset lcktestvalue = session.testvalue />
<cfoutput>#lcktestvalue#</cfoutput><br />
<cfset session.testvalue = 2 />
<cfoutput>#lcktestvalue#</cfoutput>
OUTPUT:
1
1
EXAMPLE 2:
<cfset session.testvalue1.item = 1 />
<cfset lcktestvalue1 = session.testvalue1 />
<cfoutput>#lcktestvalue1.item#</cfoutput><br />
<cfset session.testvalue1.item = 2 />
<cfoutput>#lcktestvalue1.item#</cfoutput>
OUTPUT:
1
2
I am trying to work out why the second example, updates the 'lcktestvalue1.item', when the value was only read once? I would have expected example 1 & 2 to produce the same output, and the following to produce the second example's output:
EXAMPLE 3:
<cfset session.testvalue1.item = 1 />
<cfset lcktestvalue1 = session.testvalue1 />
<cfoutput>#lcktestvalue1.item#</cfoutput><br />
<cfset session.testvalue1.item = 2 />
<cfset lcktestvalue1 = session.testvalue1 />
<cfoutput>#lcktestvalue1.item#</cfoutput>
OUTPUT:
1
2
The only reason for this behavior, I can think of, is that the second example, uses a structure inside a structure. But,I cannot expand on this concept. Can you? I really need to understand this, because I am creating a shopping cart, which makes extensive use of the methodology in example 2. It actually works fine, but I am not sure why, and I am afraid under load, it may fail?
Thank you for any help you can give me on this.
Upvotes: 1
Views: 765
Reputation: 7193
Charles, This is is expected behavior. Structures and objects are passed by reference - meaning you are actually just setting a pointer to a memory location to get at the underlying object. When the set statement is dealing with a primitive (a string, number, date etc) it copies the data into your new variable - so this:
<Cfset session.testvalue = 1/>
<cfset testvalue = session.testvalue/>
...actually creates 2 locations each containing a "1"
When you are dealing with an object however (a structure, component, function, query etc. - anything not primitive), like this:
<cfset session.testvalue.item1 = 1/>
<cfset testvalue = session.testvalue/>
The variables.testvalue variable is actually a pointer to the structure you created in the set statement (session.testvalue.item1 implicitely creates a structure).
This is important fundamental stuff - especially when dealing with CFCs, functions, application scopes etc. This post on Primitive vs complex variables explains it in more detail.
It has nothing to do with locking by the way. Unless you have some demonstratable race condition you need not go overbord with locking.
I would note that your practice here is probably not a great idea - you should probably be scoping your local vars as variables.varName any way in which case pushing session variables to that scope is not saving you any effort.
NOTE: While I was writing this Ray chimed in with a short concise answer exactly to the point (while I was being verbose).
NOTE 2: In ColdFusion there is one nuance that some find unexpected - arrays are passed by value (as a copy) and not by reference. This can throw you sometimes - and if you ever do an array of objects
Upvotes: 6
Reputation: 163
You should use Duplicate() if you want to copy/clone the structure and not just make a reference to the object stored in SESSION.
<cfset session.testvalue1.item = 1 />
<cfset lcktestvalue1 = Duplicate(session.testvalue1) />
<cfoutput>#lcktestvalue1.item#</cfoutput><br />
<cfset session.testvalue1.item = 2 />
<cfoutput>#lcktestvalue1.item#</cfoutput>
Output
1
1
Upvotes: 0
Reputation: 10857
Because your second example is making a pointer, or a reference, from the original value to the new value. You can think of it is an imaginary string between the two such that when one is changed - the other is as well. This happens with structures. You can get around this by using duplicate.
But NOTE! The need to obsessively cflock session/app/server variables has NOT been necessary for nearly ten years. You still have to worry about race conditions, but for 99% of the time this is not your concern.
Upvotes: 9