如何在ColdFusion中将变量名称作为函数名称的一部分?

时间:2011-08-26 15:10:35

标签: function variables coldfusion

我正在编写一个循环浏览注册页面上某些信息的函数。在循环中我试图基于数组调用函数。我遇到的问题实际上是正确调用函数,因为我试图将变量作为函数名的一部分。

这是我的代码:

<cfscript>
fields = arraynew(1);
fields[1] = 'r_email';
fields[2] = 'r_uname';
fields[3] = 'r_pass';

for(i = 1; i lte arraylen(fields); i = i + 1)
{
    func = fields[i].split('r_');
    func = 'validate_#func[2]#(#fields[i]#)';
}
</cfscript>

所以,我有三个函数:validate_email,validate_uname,validate_pass。如果我输入writeoutput(),并尝试输出函数的结果,它们就不起作用。

这是代码:

<cfscript>
fields = arraynew(1);
fields[1] = 'r_email';
fields[2] = 'r_uname';
fields[3] = 'r_pass';

for(i = 1; i lte arraylen(fields); i = i + 1)
{
    func = fields[i].split('r_');
    func = 'validate_#func[2]#(#fields[i]#)';
    writeoutput('#func#');
}
</cfscript>

现在,我知道当你使用writeoutput()并且你正在调用一个函数时,你需要在任一端使用哈希符号。所以,让我说我这样写:

writeoutput('#validate_#func[2]#(#fields[i]#)#');

它不起作用,因为第二个哈希符号取消了函数调用。这是函数最终的样子(电子邮件示例):

writeoutput('#validate_email('email@site.com')#');

如何使用正确的变量名替换'email'(#validate_email ...),并且仍然可以使用该功能?我希望我已经理解了这一点!

4 个答案:

答案 0 :(得分:11)

函数也是变量,因此以相同的方式对数组,结构和范围使用括号表示法,您可以使用它来访问动态变量名称(以及动态函数名称)

例如:

<cfloop index="Field" list="email,uname,pass">
    <cfset Result = Variables['validate_'&Field]( Variables['r_'&Field] ) />
    ...
</cfloop>

嗯......不太好。由于Adobe ColdFusion中的一个错误,它不能像那样工作(虽然它在其他CFML引擎中,如Railo),你必须将它分成两行,如下所示:

<cfloop index="Field" list="email,uname,pass">
    <cfset TmpFunc = Variables['validate_'&Field] />
    <cfset Result = TmpFunc( Variables['r_'&Field] ) />
    ...
</cfloop>

(这假设函数和字段都在variables范围内,如果它们不是你需要引用它们所在的范围。)

如果函数在具有state的对象中,则此方法确实存在问题,它会丢失对这些变量的引用。

在CF10上,有invoke功能。早期版本的CF需要使用cfinvoke标记。


(作为旁注,CF10确实添加了使用括号表示法引用函数结果的反向能力,即有时候有用的doSomething()[key]。)

答案 1 :(得分:1)

彼得的回答是正确的(除了我评论过的“bug”引用)。如果一个不在CFScript块的中间,则另一个选项是&lt; cfinvoke&gt;将一个字符串作为其METHOD属性值,这显然可以取任何喜欢的动态值。

对于您的具体情况,这不是那么有用,但要记住这一点很方便。

我不会使用evaluate()方法。

答案 2 :(得分:0)

我将在ColdFusion 6.1之前添加它并转移到Java,evaluate()始终被认为是性能的诅咒,但是从6.1开始它只是评估表达式,然后创建一个内联的PageContext,其中包含字符串作为其代码。

非常光滑,非常高效。

因此,实现目标的最简单,最直接的方法是:

<cfset result = evaluate("validate_#Field#(variables.r_#Field#)") />

假设您有一个名为“username”的字段,这将等同于以下方法调用:

<cfset result = validate_username(variables.r_username) />

及其返回的内容将分配给variables.result。

在测试中,它实际上优于将方法重新分配给新名称的括号表示技术。我目前没有统计数据,但速度更快,因为包含比变量赋值更快(并且在解析/编译的不同阶段发生)。

答案 3 :(得分:0)

此问题的另一种方法是使用UDF,如下所示:

    <cffunction name="callMethod">
        <cfargument name="methodName" type="string" required="true" />
        <cfargument name="methodArgs" type="struct" default="#{}#" />
        <cfset var rslt = 0 />
        <cfinvoke method="#arguments.methodName#" argumentcollection="#arguments.methodArgs#" returnvariable="rslt" />
        <!--- account for the possibility that the method call wiped out the rslt variable --->
        <cfif structKeyExists(local,'rslt')>
            <cfreturn rslt />
        </cfif>
    </cffunction>

如果你需要,你可以这样:

    <cfinclude template="invokerudf.cfm" />
    <cfscript>...</cfscript>

或将其包装在标签中并将其扔进CFC:

<cfset retval = createObject("methodinvoker").callMethod(methodName,methodArgs) />

有许多方法可以实现这一目标......现在只是抛出各种想法。