我正在编写一个循环浏览注册页面上某些信息的函数。在循环中我试图基于数组调用函数。我遇到的问题实际上是正确调用函数,因为我试图将变量作为函数名的一部分。
这是我的代码:
<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 ...),并且仍然可以使用该功能?我希望我已经理解了这一点!
答案 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) />
有许多方法可以实现这一目标......现在只是抛出各种想法。