【问题标题】:How can I call a variable name as part of a function name in ColdFusion?如何在 ColdFusion 中将变量名作为函数名的一部分调用?
【发布时间】:2011-08-26 15:10:35
【问题描述】:

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

这是我的代码:

<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')#');

如何将“电子邮件”(#validate_email...)替换为正确的变量名,并且仍然可以使用该功能?我希望我已经让这变得可以理解了!

【问题讨论】:

    标签: function variables coldfusion


    【解决方案1】:

    函数也是变量,因此您可以使用括号表示法来表示数组、结构和作用域,您可以使用它来访问动态变量名称(以及动态函数名称)

    例如:

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

    嗯……不完全是。由于 Adob​​e ColdFusion 中的一个错误,它不能像这样工作(尽管它在其他 CFML 引擎中,如 Railo),你必须将它分成两行,如下所示:

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

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

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

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


    (作为旁注,CF10 确实添加了使用括号表示法引用函数结果的逆功能,即 doSomething()[key],这有时会派上用场。)

    【讨论】:

    • 这不是 CF 中的错误,Peter:它只是从未被实施过。您可能想要修改您的评论以达到这种效果。否则,一个准确的答案。
    • Variables.Bob()Variables['Bob']() 之间应该没有区别 - 但是,第二个会引发错误。我称之为括号符号中的错误,而不是未实现的功能。
    • 谢谢。我收到的两个建议都很好。我是 CF 的新手,所以我会随波逐流,使用这个而不是另一个。另一个更容易一些,但如果它有问题,我不想参与其中!再次感谢!
    【解决方案2】:

    彼得的回答很到位(除了我评论的“错误”参考)。如果不在 CFScript 块的中间,另一种选择是 将字符串作为其 METHOD 属性值,并且显然可以采用任何喜欢的动态值。

    这对您的具体情况没有多大帮助,但记住它很方便。

    我不会使用 evaluate() 方法。

    【讨论】:

      【解决方案3】:

      我要补充一点,在 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。

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

      【讨论】:

      • 至于亚当对评估()的警告,除了愚蠢并使用它来评估用户提供的值(比如允许用户基本上输入代码 - 是的,它已经完成)没有理由避免使用这种方法。没有挥之不去的性能或安全问题。
      【解决方案4】:

      解决此问题的另一种方法是使用如下 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) />
      

      有很多很多方法可以实现这一点......现在只是把各种想法扔在那里。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-11-06
        • 1970-01-01
        • 1970-01-01
        • 2013-12-23
        • 2017-05-24
        • 2014-10-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多