ColdFusion has a TON of amazing functions built right into. The problem (in a weird way) with some of these functions is that they have great names. This is a good thing most of the time, but sometimes, a function name is so good that you want to use it for another purpose. Image a situation where you have a custom data type. You might want to slap a ToString() method on it, DataType::ToString(). Or what about a bean that has some sort of validation issues. You might want to slap an IsValid() method on it, Bean::IsValid().
If you try to define these methods within the ColdFusion component you are creating as such:
<cfcomponent displayname="Bean" output="false"> <cffunction name="IsValid" access="public" returntype="boolean" output="false" hint="Determines if bean data is valid."> <!--- For testing just return true. ---> <cfreturn true /> </cffunction> </cfcomponent>
... ColdFusion throws the compile-time error:
The names of user defined functions cannot be the same as built-in ColdFusion functions. The name IsValid used for a user defined function is the name of a built-in ColdFusion function.
This is a shame since IsValid() would be such a sweet member method of the ColdFusion component right? You have two options at this point: One, choose a different name or Two, declare the method indirectly using method pointers.
Option one is lame. Why change the name of the method you want just because ColdFusion doesn't like it. The reason you chose the name (and the reason ColdFusion has a method with the same name) is because that name rocks! Let's not run and hide.
Option two is the one I would suggest. It is slightly kludgy but it accomplishes exactly what you want it to do with minimal work. Remember, the errors we get her are compile time errors, not run time errors. Also remember that pretty much everything in ColdFusion is an object, including variables and user defined functions. We can use this to our advantage.
To get around the compile time issue, we simply cannot name the function exactly how we want it to be named. Sorry. But, we can name a variable with that name. Then, at run time, we can set that variable to point towards the method we want. This, for all intents and purposes, is the same thing as defining a method with the chosen name. Here is the above example with our method:
<cfcomponent displayname="Bean" output="false"> <!--- Set method access pointers. ---> <cfset THIS.IsValid = $IsValid /> <cffunction name="$IsValid" access="private" returntype="boolean" output="false" hint="Determines if bean data is valid."> <!--- For testing just return true. ---> <cfreturn true /> </cffunction> <cffunction name="IsNotValid" access="public" returntype="boolean" output="false" hint="Determines if bean data is not valid."> <cfreturn NOT THIS.IsValid() /> </cffunction> </cfcomponent>
Notice that in the ColdFusion component's pseudo constructor (the code outside of method definitions), I am creating a public, THIS-scoped variable of the same name (as the member function I want to create). I am setting this variable to be a pointer to the first class object which is our private, VARIABLES-scoped member method. When I declare the method I prepend the name with the "$" to make sure the code compiles. Since the method gets validated at compile time, this ColdFusion component does not have any parsing errors. However, since the pseudo constructor runs a run time, we end up with a public, THIS-scoped method with our desired name.
<!--- Create the bean. ---> <cfset objBean = CreateObject( "component", "Bean" ) /> <!--- Call test methods. ---> #objBean.IsValid()# #objBean.IsNotValid()#
... gives us:
Now, when calling this method from within the ColdFusion component (say from the IsNotValid() method), you MUST scope the method call. If you do not, ColdFusion first looks in its list of methods before checking the scopes of the ColdFusion component itself. Not scoping will result in the error:
Parameter validation error for function IsValid. The function allows 3 parameters, but found 0.
Personally, I think scoping all of your method calls is a good idea any way. To me, this ups readability of the code. The down side of this is that since we calling a scoped variable (IsValid) then we have to use the appropriate scope during the method invocation. This however, should not be a big deal, but something to note.
If anyone knows of a way to do this WITHOUT having the intermediary step, I am all ears.
Want to use code from this post? Check out the license.