I recently had a chance to listen to the latest edition of the This Week in ColdFusion Podcast wherein design patterns are discussed. One of the design patterns that Brian Carr talks about in the podcast is the Decorator Pattern. As an example, Brian describes how you can use the dynamic nature of ColdFusion to assign a function to a variable and then add that function to an object at runtime (this is also known as "method injection"). Bob Silverberg, who was a guest on the podcast then asked Brian whether the injected method would show up in the object's metadata if you called the getMetaData() function on it. Brian didn't know for sure, but he and Bob agreed that it was unlikely. This piqued my curiosity, so I set about to test this myself.
First, I built a very simple component -- person.cfc
<cfcomponent> <cffunction name="init" access="public" returntype="any"> <cfset variables.name = "Tony Garcia" /> <cfreturn this /> </cffunction> </cfcomponent>
This component only has an init() method, which sets variables.name to "Tony Garcia" and returns the instance.
Next, I wrote this template called injectiontest.cfm.
<cffunction name="testMethod" access="public" returntype="string"> <cfreturn variables.name /> </cffunction> <cfset tony = createObject( "component","person" ).init() /> <cfdump var="#getMetaData( tony )#" label="Before Injection" /> <cfset getName = testMethod /> <cfset tony.getName = getName /> <cfdump var="#getMetaData( tony )#" label="After Injection" /> The name is: <cfoutput> #tony.getName()# </cfoutput>
It's pretty clear what's going on here. First I define a function named "testMethod". Then I create an instance of person.cfc and dump out its metadata. I then assign testMethod() to a variable and inject it into my object using the name "getName" for the method (since that's what it does). I dump the metadata again after the injection and then just test the method itself by outputting its return value.
Here is the output of the dump before injection using ColdFusion 9:
As expected, only the init() method appears in the array of functions. This is the dump after the method injection:
The only function that appears is still the init() method. So Brian and Bob were correct in their suspicions. But then, since I work alot with Railo, I decided to run the code in Railo 3.1. Here is the dump before the method injection (now I'm just showing the functions element):
Again, we only see the init() function. But notice that the dump gives us some more info about the function compared to the CF9 dump. Take special note of the "owner" element, which is the path to the cfc.
Now here is the dump after the method injection:
So the Railo dump of the object's metadata does indeed include the injected method! Another interesting observation is that the name given for the method is "testMethod", not "getName", so it uses the original name of the function that was injected, not the name it was assigned to in the object. Also, note that the "owner" element is the path to the template where the injected method was defined. So if you're doing some fancy programming against metadata, the "owner" element may be used to check whether the method in question is built-in to the object or was injected.
Anyway, I thought this was pretty interesting so I thought I'd share.