4 Replies Latest reply: Feb 17, 2012 12:49 PM by BKBK RSS

    Instantiate a component object

    GKiew

      Hi! I'm not too clear with instantiating a component object and using cfinvoke to call the function.

      To make it clear I'm going to use an easy example as follow:

      Supposed I have a registration application where all it does was just getting user information, validate them and insert them into a table.

      Since this functionality will be used repeatedly by many new users, I made it into a component.

       

      So I will have:

      MyComponent.cfc : 

      <cfcomponent displayname="UserRegistration" output="false">

          <CFFUNCTION name="Init" access="public" returntype="any" output="false" hint="Returns an initialized component instance.">
                  <cfreturn THIS />
          </CFFUNCTION>  

           

       

       

        <CFFUNCTION name="Validate_and_Store_User" hint="Store registration data" >
        <cfargument name="st_NewUser" type="Struct" required="True">

       

       

          There will be user validation and SQL Insert script in here

       

        </CFFUNCTION>

       

       


      </cfcomponent>

       

       

      The Calling page is: RegistrationPage.cfm:

      I'm calling it this way:

      1. Instantiate the component object:

          <cfset objRegistration = createObject('component', 'MyComponent') />

      then call the UDF:

       

       

      <CFINVOKE  component="#objRegistration#" method="Validate_and_Store_User" st_NewUser ="#st_NewUser#">

       

       

       

       

      My question is:

      When a new user is trying to register, first, the component object is instantiated and then the UDF is called

      But when there are more new users registering at the same time, does it means the component object got instantiated over and over again instead of just once?

      Looking at the code, CF will run <cfset objRegistration = createObject('component', 'MyComponent') /> everytime a user is registering and this mean an instant of that component is created, so every user will instantiate a component object? is this how it is supposed to work?

      I'm just using a registration as an example. My core confusion is on whether or not an instant of component need to be created for each user.

      Thanks!

        • 1. Re: Instantiate a component object
          Owain North Community Member

          Okay, I wouldn't bother using both cfinvoke in this case, there's no need. You're right, putting this in your registration page will result in a new copy of the cfc being created on every request. There are a few options.

           

          If you're going to use more than one method from the component, I'd create an instance first then call the methods:

           

          <cfset MyCFC = createObject("component", "MyComponent") />

          <cfset MyCFC.validateAndStoreUser(st_NewUser) />

          <cfset MyCFC.someOtherMethod() />

           

          If you're only calling one method, you can do it directly, destroying the CFC immediately after it's used:

           

          <cfset ReturnResult = createObject("component", "MyComponent").validateAndStoreUser(st_NewUser) />

           

          However a better way (if the cfc is basically "static") is to create it at the Application level. In your Application.cfc's onApplicationStart() method:

           

          <cfset application.MyCFC = createObject("component", "MyComponent") />

           

          Then in your code, reference the *one* instance of the CFC without having to create/destroy it every time, so more memory efficient:

           

          <cfset ReturnResult = application.MyCFC.validateAndStoreUser(st_NewUser) />

           

          If the component is just a bunch of methods, create it at the Application level. If it's a Class, then you need a createObject() for each one - i.e. if you had a Person.cfc with a name property, that'd be a createObject() for each one. If they're just static CFCs, one on the Application scope is the way to go.

           

          Very good explanation on your part by the way, nice to have someone ask a sensible, comprehensible and well thought-out question for a change.

           

          O.

          • 2. Re: Instantiate a component object
            GKiew Community Member

            Hi Owain, thanks for taking the time to help me understand how to work with component object. I appreciate it very much.

            One of the example you wrote:

            "If you're going to use more than one method from the component, I'd create an instance first then call the methods:

             

            <cfset MyCFC = createObject("component", "MyComponent") />

            <cfset MyCFC.validateAndStoreUser(st_NewUser) />

            <cfset MyCFC.someOtherMethod() /> "

             

            This technique makes a lot of sense because calling more than one functions within that component object instce avoid the necessity of instantiating another instance of comp. object that already created.

            But I'm still unclear when there are more than one users accessing this component. Assuming I have a component with 3 UDFs:

            - 1 UDF is for validating required fields

            - 1 UDF is for validating and creating temporary username and password and

            - 1 UDF is for inserting registration information to a table

             

            If we're talking about 1 user doing a registration, than per your explanation, 1 instance will be created and than using that instance all the 3 UDFs are called without having to create 3 instances to get to each of the UDF. Up to this point I'm clear.

            On the other hand, when I have 10 users doing registration at the approximately the same time then there will still be 10 instances created for each user, right? 

            • 3. Re: Instantiate a component object
              Owain North Community Member

              ColdFusion doesn't have the concept of Static classes, so if three people all access the same page, and in that page you do a createObject() then yes, you have three separate objects each with their own properties in their own block of memory. There is absolutely nothing linking them at all.

               

              The only scope CF has where you can share objects between users (sessions) is the Application scope; therefore if you did the onApplicationStart method I said about and referenced *that* in all three requests, they are all truly using the same object in the same lump of memory. Therefore:

               

              On the other hand, when I have 10 users doing registration at the approximately the same time then there will still be 10 instances created for each user, right?

              Correct, but badly worded - there will not be 10 instances created for each user, there will be ten instances created - one for each user.

               

              You can try this out for yourself; inside your CFC create a property called this.MyCounter, and set it to 1:

               

              <cfcomponent>

                <cfset this.MyCounter = 1 />

              ... methods etc

              </cfcomponent>

               

              If anywhere on your page you do this:

              <cfset obj = createObject("component", "MyComponent") />

              <cfset obj.MyCounter++ />

              <cfoutput>#obj.MyCounter#</cfoutput>

               

              ...then you'll only ever get "2" returned to the page, because each page request is creating a new instance. If however you did the Application-level method:

               

              <cfset application.MyCfc.MyCounter++ />

              <cfoutput>#application.MyCfc.MyCounter#</cfoutput>

               

              ...then you'll see it increasing with every page refresh until the application timeout is reached.

               

              As an aside, if you do have properties stored inside your CFC that's then stored in the Application scope, then remember the whole point is that it can be references by many different pages - all in different threads. You therefore need to start using CFLOCK, but that's a separate discussion. As long as your CFC just has static methods which take in arguments and return values, this isn't a concern.

               

              Hope that helps.

              O.

              • 4. Re: Instantiate a component object
                BKBK MVP

                Owain North wrote:

                 

                The only scope CF has where you can share objects between users (sessions) is the Application scope; therefore if you did the onApplicationStart method I said about and referenced *that* in all three requests, they are all truly using the same object in the same lump of memory.

                However, they never share ownership of the object at the same time.