2011-08-26 88 views
5

我正在写一个函数,循环注册页面上的一些信息。在循环内,我试图调用基于数组的函数。我遇到的问题实际上是正确调用函数,因为我试图将变量作为函数名称的一部分。如何在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 protected]')#'); 

我怎样才能用正确的变量名称替换“电子邮件”(#validate_email ......),而且还有功能的工作?我希望我能够理解这一点!

回答

10

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

例如:

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

那么......不完全。由于Adobe ColdFusion,请一个bug,不喜欢的工作(尽管它在其他CFML引擎,如Railo),你必须把它分成两行,像这样:

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

(这假设两个函数和字段都在variables范围内,如果他们不需要参考他们所在的范围)。

如果函数处于状态为object的对象中,则此方法存在问题失去对这些变量的引用。

在CF10上,有invoke函数。较早版本的CF需要使用cfinvoke标签。


(作为一个方面说明,CF10确实添加了参考作用的结果与括号标记的反能力,即doSomething()[key]这有时进来有用。)

+0

这不是CF中的错误,Peter:它从来没有实现过。你可能想修改你的评论来达到这个效果。否则就地答复。 –

+3

'Variables.Bob()'和'Variables ['Bob']()'应该没有区别,但是第二个抛出错误。我称这是一个括号表示中的错误,而不是一个未实现的功能。 –

+0

谢谢你。我收到的两个建议都很好。我是CF的新手,所以我会和人群一起使用,而不是使用其他人。另一个更容易一点,但如果有问题,我不想进入!再次感谢! –

1

彼得的回答是现货(除我评论过的“bug”引用)。如果不在CFScript块的中间,另一个选项是<cfinvoke>将一个字符串作为其METHOD属性值,并且显然可以采用任何喜欢的动态值。

对于您的具体情况,这不是那么有帮助,但记住它很方便。

我不会使用evaluate()方法。

0

我会补充说,在ColdFusion 6.1和迁移到Java之前,evaluate()总是被认为是对性能的诅咒,但从6.1开始,它只是评估表达式,然后创建一个带有包含字符串的内联PageContext作为其代码。

非常光滑,非常高效。

那么,要实现你的目标的最简单,最直接的方法是:

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

所以假设你有一个名为“用户名”栏,这将是下面的方法调用相当于:

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

以及它返回的任何内容将被分配给variables.result。

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

+0

至于Adam对evaluate()的警告,除了愚蠢并使用它来评估用户提供的值(如允许用户实质上输入代码 - 是的,它已完成),没有理由避免使用此方法。 没有挥之不去的性能或安全问题。 – jrypkahauer

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) /> 

有很多很多方法可以实现这一点......现在就把各种想法扔出去。

相关问题