ColdFusion的CFC方法能否确定自己的名称?

13

我正在创建一个API,在每个方法中我都会调用一个日志记录方法,以便进行审计和故障排除。例如:

<cffunction name="isUsernameAvailable">
    <cfset logAccess(request.userid,"isUsernameAvailable")>
    ......
</cffunction>

我希望避免手动重复方法名。有没有一种编程方式可以确定它?

我查看了GetMetaData(),但它只返回有关组件的信息(包括所有方法),而没有关于当前调用哪个方法的任何信息。

5个回答

12

现在有三种方法:

如果您使用的是 ColdFusion 9.0 或更高版本,则可以使用名为 GetFunctionCalledName() 的函数来获取您正在查找的内容。 http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WS7cc222be8a31a47d-6e8b7083122cebfc8f2-8000.html

或者

使用 ColdSpring 和面向方面编程 (http://www.coldspringframework.org/coldspring/examples/quickstart/index.cfm?page=aop) 来为您处理此操作。

或者

使用 cfthrow 来生成包含所需信息的堆栈跟踪:

<cffunction name="determineFunction" output="FALSE" access="public"  returntype="string" hint="" >
<cfset var functionName ="" />
<cfset var i = 0 />
<cfset var stackTraceArray = "" />
<cftry>
<cfthrow />
<cfcatch type="any">
    <cfset stacktraceArray = ListToArray(Replace(cfcatch.stacktrace, "at ", " | ", "All"), "|") />

    <!---Rip the right rows out of the stacktrace --->
    <cfloop index ="i" to="1" from="#ArrayLen(stackTraceArray)#" step="-1">
        <cfif not findNoCase("runFunction", stackTraceArray[i]) or FindNoCase("determineFunction", stackTraceArray[i])>
            <cfset arrayDeleteAt(stackTraceArray, i) />
        </cfif>
    </cfloop>

    <!---Whittle down the string to the func name --->
    <cfset functionName =GetToken(stacktraceArray[1], 1, ".") />
    <cfset functionName =GetToken(functionName, 2, "$")/>
    <cfset functionName =ReplaceNoCase(functionName, "func", "", "once")/>

    <cfreturn functionName />
</cfcatch>
</cftry></cffunction>

我的建议是使用getFunctionCalledName,或者如果不在CF 9 ColdSpring上,则可能会为您带来其他一些东西。


冷泉的选择不错,但你会认为它不应该这么复杂。 - ethyreal

4

我同意tpryan的观点。ColdSpring让这个过程非常简单。不过,这里还有另一种选择。你可以解析CFC文件本身而不是解析堆栈跟踪。

<cffunction name="foo" displayname="foo" hint="this is just a test function" access="public" returntype="string">
    <cfset var test = getFunctionName(getMetaData().path, getPageContext().getCurrentLineNo()) />
    <cfreturn test />
</cffunction>

<cffunction name="getFunctionName" hint="returns the function name based on the line number" access="public" returntype="string">
    <cfargument name="filepath" type="string" required="true" />
    <cfargument name="linenum" type="any" required="true" />
    <cfset var line = "" />
    <cfset var functionName = "" />
    <cfset var i = 1 />
    <!---- loop over CFC by line ---->
    <cfloop file="#ARGUMENTS.filepath#" index="line">
        <cfif findNoCase('cffunction', line, 1)>
            <cfset functionName = line />
        </cfif>
        <cfif i EQ ARGUMENTS.linenum><cfbreak /></cfif>
        <cfset i++ />
    </cfloop>
    <!---- parse function name ---->
    <cfset functionName = REMatchNoCase("(\bname=[""|'])+[a-z]*[""|']", functionName) />
    <cfset functionName = REMatchNoCase("[""']+[a-z]*[""']", functionName[1]) />
    <cfset functionName = ReReplaceNoCase(functionName[1], "[""']", "", "all") />
    <!---- return success ---->
    <cfreturn functionName />
</cffunction>

以上内容是针对 ColdFusion 8 写的。CFLOOP 增加了对逐行循环文件的支持(不会将整个文件读入内存)。我进行了一些测试,比较了堆栈跟踪方法和文件解析方法。在从单个 CFM 模板直接调用的小型 CFC 上,两种方法表现相同。显然,如果您有非常大的 CFC,则解析方法可能会慢一些。另一方面,如果您有一个大的堆栈跟踪(例如,如果您正在使用任何流行的框架),则文件解析可能更快。

-= Viva ColdFusion =-


1

你可以尝试这个:

 <cffunction name="getFunctionName" returntype="any">
        <cfset meta =getMetaData(this)> 
        <cfreturn meta.functions[numberOfFunction].name>
    </cffunction>

我尝试了各种方法,但函数似乎是以字母表相反的顺序添加到函数数组中,这并不准确。这似乎很受限制(并没有解决问题)。我想一些本地的Java代码可以被调用,但我需要研究一下。

这个这个看起来是相关内部函数的有趣阅读。

关于coldspring的其他答案:我在这篇深度文章中发现了关于函数元数据的内容。

相关问题:如何在ColdFusion中获取扩展我的组件的组件名称?


1

我想到了另一种可能行得通的方法。

设置一个类似这样的OnMissingMethod:

<cffunction name="onMissingMethod">
    <cfargument name="missingMethodName" type="string"> 
    <cfargument name="missingMethodNameArguments" type="struct">

    <cfset var tmpReturn = "">
    <cfset var functionToCallName = "Hidden" & Arguments.missingMethodName>
    <cfset arguments.missingMethodArguments.calledMethodName = Arguments.missingMethodName>
    <cfinvoke method="#functionToCallName#" argumentcollection="#Arguments.missingMethodArguments#" returnvariable="tmpReturn" />
    <cfreturn tmpReturn>
</cffunction>

然后使用前缀(在此示例中为“Hidden”)命名每个常规方法,并将其标记为私有。因此,我的初始示例将变为:

<cffunction name="HiddenisUsernameAvailable" access="private">
    <cfset logAccess(request.userid,Arguments.calledMethodName)>
    ......
</cffunction>

现在所有的调用都将被onMissingMethod拦截,它会将方法名添加到传递给真实方法的参数中。

我看到的缺点是内省不再正常工作,而且您必须使用命名参数来调用所有函数。如果您没有使用命名参数,则args将随机更改缺失的方法名称参数结构中的顺序。


太有创意了!我从来没有想过使用函数包装器。 - ethyreal

0

getFunctionCalledName() 可以获取当前方法的名称。


你可以提供一个解决方案的例子,并说明它如何帮助问题的提出者,从而改进你的回答。 - Tyler2P

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接