4

I am hoping that someone can explain this behavior, as I find it pretty aggravating. I have a parent class with an OnMissingMethod implementation to provide implicit getters/setters (old CF8 application)

if I instantiate the child class as foo and call foo.getBar() from an external file, it successfully triggers OnMissingMethod, but if within the foo class itself I call getBar() it doesn't. The only way it will trigger OnMissingMethod is if I use this.getBar() which I don't like for aesthetic and code inconsistency reasons.

tldr; here is a code example... try it yourself.

Foo.cfc

<cfcomponent output="false" extends="Parent">

        <cffunction name="init" output="false" returntype="Foo">
            <cfreturn this />
        </cffunction>

        <cffunction name="getInternalBar_workie">
            <cfreturn this.getBar() />
        </cffunction>

        <cffunction name="getInternalBar_noworkie">
            <cfreturn getBar() />
        </cffunction>

</cfcomponent>

Parent.cfc

<cfcomponent output="false">

    <cffunction name="OnMissingMethod">
        <!--- always return true for this example --->
        <cfreturn true />
    </cffunction>

</cfcomponent>

foobar.cfm

<cfset foo = CreateObject( "component", "Foo").init() />

<!--- this works --->
<cfdump var="#foo.getBar()#" /><br/>
<!--- this works --->
<cfdump var="#foo.getInternalBar_workie()#" /><br/>
<!--- this fails --->
<cfdump var="#foo.getInternalBar_noworkie()#" />

Can anyone explain why the 'this' scope must be used for OnMissingMethod to work properly when calling from the class itself? Is there a better workaround?

Dave Shuck
  • 583
  • 1
  • 6
  • 19
  • After reviewing Adam's answer, it looks like you're stuck. What is the actual problem you're trying to solve by calling non-existent methods in this manner? – imthepitts Jul 09 '13 at 23:04
  • I have a large amount of services (+/-1000) that all have dependencies with other services. I am using ColdSpring to manage the DI and am injecting services using property injection. This of course requires that there is an available getter for the injected service inside the target service. Rather than explicitly write out thousands of boiler plate getter methods that all do the same thing, I have made all services extend a BaseService, and in that class I have an OnMissingMethod that looks for getFooService() and setFooService(fooService) patterns and does... – Dave Shuck Jul 10 '13 at 15:29
  • ...the appropriate setting work placing them in a variables["_dependencies"] collection in the target. The drawback is that while setting works properly, anytime I want to reference the injected service I either need to do: variables["_dependencies"].fooService OR this.getFooService(). The problem I have with using this.getFooService() is that it is inconsistent from how I call other methods within the same class. It's not a critical problem of course, but that doesn't mean I like it. – Dave Shuck Jul 10 '13 at 15:29

2 Answers2

2

Thank goodness for Google. I didn't know the answer, but googled "coldfusion onmissingmethod this scope" and the first match explained your situation in one of the comments. I feel bad for reproducing Elliott's work, but it gets your question answered:

[...]

CFCs are just proxied pages. CreateObject() returns a TemplateProxy that wraps the CFPage that is your actual code.

[...]

when you call the function as "this.getFoo()" or from the outside as "myObject.getFoo()", instead what happens is that it calls a method on the TemplateProxy for invoking a method, which in turn calls the function on the proxied page.

OnMissingMethod handling exists in the invoke() function on the TemplateProxy, thus it only works from outside or through the this scope.

[...]

Adam Cameron
  • 29,677
  • 4
  • 37
  • 78
-1

This shows the difference between public members and private members. The call to getBar() isn't a shortcut for the public this.getBar(). It's a shortcut for the private variables.getBar(), which doesn't exist in Parent.cfc. The private function variables.getBar() only exists in the variables scope of Foo.cfc. Because it's a public function, it is also accessible as a public member of the entire instantiated class within the this scope. The parent can't refer to private variables inside the extended (child) object. But the parent can refer to the public members.

imthepitts
  • 1,647
  • 10
  • 9