Wednesday, December 30, 2015

Form structure deep-dive

Sometimes it pays to peek under the hoods a little. Inspired by Ben Nadel's GetPageContext() exploration (and my own need to upload multiple files easily), I thought I would take everyone on a tour of the form object. That's right folks, it's not just a scope. There are actually a lot of methods attached to form which might occasionally prove useful.
To start off, form is an instance of coldfusion.filter.FormScope, which lives in cfusion\lib\cfusion.jar. If you're comfortable reading Java bytecode, you may find it interesting to inspect. Here are the methods it exposes publicly:

  • String getEncoding() - Not a terribly interesting. Tells you your text encoding. For example, mine returned "UTF-8"
  • List<com.oreilly.servlet.multipart.Part> getPartsArray() - Very interesting. Ever look at HTTP headers in your browser's inspector? Those go in here. If files are being submitted, you can get useful information by looking at the values here. I'll go into more depth on this later, when I talk about how I used this to properly support file uploads.
  • coldfusion.util.FastHashtable getTempFiles() - On the ColdFusion side, FastHashtable is a struct. Every file submitted to this page will have an entry in this struct, indexed by the form field's name. The items stored in the struct are standard Java Files, pointing to the (temporary) place on your server where the file has been uploaded. For example, I just uploaded a text file which landed as C:\Coldfusion10\cfusion\runtime\conf\Catalina\localhost\tmp\neotmp6148837847015402066.tmp. You'll want to go through cffile to put that file somewhere useful.
  • void processServerSideValidation() - My guess is that this is called by ColdFusion to perform validation on parameters that were passed in. You shouldn't have a need to call this yourself.
  • void processServerSideValidation() - Another function that is probably only needed internally by ColdFusion
  • void setEncoding(String) - The partner to getEncoding().
  • void setEncoding(String, HttpServletRequest, ServletContext) - Another partner to getEncoding(). Do not touch.
  • int size() - Tells you the number of items in the form scope (includes form.fieldNames)
And that's it (at least when it comes to public method specific to FormScope; the LocalScope class it inherits from has more). Next time, I'll talk about how I was able to put the above information to work.

Monday, December 28, 2015

Are scoped variables faster?

tldr: No

At the recent ColdFusion conference, it was recommended that you always scope variables for a speed increase. Simply including a variable #like_so# requires the engine to potentially look through several scopes until it finds the correct one.

The main place this would matter, of course, is inside a large loop. Specifically, you would want to scope fields inside a query loop.

I wrote the following code to test this out. q is a query of 10,000 rows.
 <cftimer label="unscoped" type="debug">  
      <cfloop query="q">  
           <p>#p1# #p2# #p3# #p4# #p5# #p1# #p2# #p3# #p4# #p5#</p>  
      </cfloop>  
 </cftimer>  
 <cftimer label="scoped" type="debug">  
      <cfloop query="q">  
           <p>#q.p1# #q.p2# #q.p3# #q.p4# #q.p5# #q.p1# #q.p2# #q.p3# #q.p4# #q.p5#</p>  
      </cfloop>  
 </cftimer>  

Results:
unscoped: 48ms
scoped: 75ms

Several runs (and reversing the order of two loops) all gave similar numbers on both CF10 and CF11. So I'm afraid that, at least for Adobe implementations of Coldfusion, you are better off not scoping your variables.

(I still advise scoping arguments, though.)