One of the new language additions to ColdFusion Zeus is the ability to get the current callstack. If that sounds Greek to you, it's simply the ability for a function to know who call it, who called that guy, and so on. It sounds confusing, but a few quick examples will help.
In our first example, I've got a call to a UDF that calls another UDF. That UDF runs one of the two new functions introduced in this blog post, callStackGet.
function child() {
return callStackGet();
}
</cfscript> <cfdump var="#top()#">
<cfscript>
function top() {
return child();
}
callStackGet returns an array of "invokers", or basically, how in the heck did we get here. Looking at the code it's easy enough to tell that child was called by top, and top was called by our cfdump. When displayed, this is what we get.
Notice the array is ordered from most immediate to the final originator of the caller. Also note that the function is labelled where appropriate. How about a slightly more complex example? Consider the code below.
function parent() {
return child();
} function child() {
return new some().test();
}
</cfscript> <cfdump var="#grandparent()#">
<cfscript>
function grandparent() {
return parent();
}
This is similar to our earlier code, but now child is invoking a CFC as well. Here is some.cfc.
function test() {
return callStackGet();
} }
component {
And the result...
As expected, it picks up on the different file in the CFC.
Another option is callstackDump. callstackDump returns a string based version of the callstack. It supports logging to a file, logging to console, or simply printing to the browser. Here's a modified form of the CFM we last tested with.
function parent() {
callstackDump(expandPath("./callstack.log"));
callstackDump("browser");
return child();
} function child() {
return new some().test();
}
</cfscript> <cfdump var="#grandparent()#">
<cfscript>
function grandparent() {
return parent();
}
Notice I've added two calls to callstackDump. Most likely, this is a more real world example as you won't probably ever return a callstack to the user. Here's an example of how it prints to my browser.
And there you have it folks. I'll be posting another Zeus preview before the Christmas break.
Archived Comments
This is my favorite new feature so far! Can't wait to use this.
I'm with Ryan. I have been wanting this for a long time. To me, this is a real reason to upgrade.
Cool to hear you guys like this!
Great! I like the stack trace.
I wish both the function names replaced with each other.
callstackDump() name should be callStackGet() and callStackGet() name should be callstackDump()
@Ray,
Does the name of the function listed depend on what it was named in the file? Or, what it was named at runtime (ie. is it the value that getFunctionCalledName() would return within a given function)?
Under most circumstances it would be the same, right? Or are you talking about a case where you create a copy of a UDF/method? If you can give me an easy test, I can run it and tell you.
Yeah, mostly the same; just wondering how it would work if I had copies of a method reference. Imagine I had a method that was a generic getter:
function getXYZ():
var name = getFunctionCalledName();
var prop = reReplace( name, "^get", "", "one" );
return( variables[ prop ] );
The, I could have something like this in my CFC:
this.getName = this.getDOB = this.getDateCreated = this.getXYZ;
I'm not saying I would do that, especially now that we have synthesized accessors; but, just curious what name would be returned in the callstack.
If you could ping me direct via email with code I could run, I'll drop in callStackDump and tell you.
Done :)
So I tested Ben's code. It shows that we report the REAL name of the function, not the function it was called as. Is that a bug? I have NO idea. Yall decide. ;)
+1
Just read this.
Very similar to the trace() function that is floating about as a UDF. However, that doesn't make it any less welcome! Finally, easy child-parent based debugging!
Having said that... CFSCRIPT... Never have liked it! As much as I appreciate trying to homogenise the syntax of CF with JS and others, in my mind it still makes code more difficult to read and still has differences to other languages, so the problem still remains - my point being I still prefer the tag-based CF because it looks different to, for example JS, so there's no confusion when looking at code.
It's very early, so that may have been gibberish!
@Michael: I only use all script in my CFCs, which won't have JS or HTML in them so there is no chance of confusion. I definitely still use tag based CF all the time.