【问题标题】:Is there a way to interact directly with the nameless declared arguments scope in CF9/10?有没有办法直接与 CF9/10 中的无名声明参数范围进行交互?
【发布时间】:2013-09-14 20:58:44
【问题描述】:

如果你不知道我在说什么,试试这个:

<cffunction name="myFunc">
    <cfargument name="myArg" default="foobar">
    <cfdump var="#local#" label="local and arguments scopes before deleting myArg">
    <cfset StructDelete(arguments, "myArg")>
    <cfdump var="#local#" label="local and arguments scopes after deleting myArg">
    <cfset StructDelete(local, "arguments")>
    <cfdump var="#local#" label="local scope after deleting arguments scope">
    <cftry>
        <cfset writeOutput("myArg still exists, and evaluates to: " & myArg)>
        <cfcatch>
            <cfset writeOutput("myArg no longer exists")>
        </cfcatch>
    </cftry>
</cffunction>

<cfset myFunc()>

<cfexit>

如果您运行该代码,您会发现即使在删除参数和参数范围之后,您仍然可以通过非范围引用访问声明的参数。这意味着存在一个未命名的范围,其中包含声明的参数的副本或值的引用。我试图找出是否有某种方法可以直接使用此范围,例如未记录的范围名称或底层 Java 中的 getter 方法。暂时将其视为一个纯粹的学术问题,因为我很确定我可能想到的任何用例都会被大多数著名的程序员所忽视。

编辑

我认为提供我当前对 UDF 范围的理解的细分可能很有用,因为 Adam 的回答有点模糊了界限。为简单起见,我将排除特定于 cfc 的内容...

  • 没有范围或“var”关键字定义的变量被放置在调用页面的变量范围内。

  • local 范围包含在函数执行期间使用 var 关键字或 local 范围名称(例如 local .myvar,本地[“myvar”])。它还包含 arguments 范围。

  • arguments 范围包含函数调用中声明或传递的每个参数。变量也可以在函数执行期间添加到其中或从中删除。 arguments 作用域是 local 作用域的成员,可以这样引用(例如 local.arguments.myvar、local.arguments[1]),但它也可以被独立引用(例如 arguments.myvar、arguments[1])。

  • 有一个无名作用域,其中包含 已声明 的每个参数的副本(即包含在 cfargument 标记中,或 cfscript 中函数定义开头的括号中)。我观察到与此范围相关的以下特征和行为:

    • 未声明的参数未添加到无名作用域。

    • 声明参数是使变量进入无名作用域的唯一方法,ColdFusion 似乎不会在任何其他情况下使用它。

    • arguments 范围不同,无名范围与 local 范围没有明显关系。

    • 无名作用域变量的值及其 参数 作用域对应的值要么是对同一值的引用,要么以这样一种方式相互连接,即更改一个变量会同时改变两者.

    • 将新变量动态添加到 arguments 将其添加到无名范围(因为只有 已声明的 参数添加到无名作用域)。

    • 您不能通过常规方式(即 StructDelete()、ArrayDeleteAt())删除无名作用域变量。您可以删除其 arguments 范围的对应项,但该值将通过无范围的引用保持可用。 (有关完全删除已声明参数的方法,请参阅 Henry 的回答)。

    • arguments 中删除声明的参数后,可以独立设置其无名范围对应项的值。即使将具有相同名称的变量添加回 arguments,这仍然适用。

    • CF9 和 CF10 中存在无名作用域,但(正如 Henry 和 Adam 指出的)Railo 中不存在。

    • 无名作用域位于 CF 作用域层次结构的绝对顶部,在使用无作用域引用时优先于所有其他作用域。这一点,连同前面关于不可删除性的观点,可能是关于无名作用域最重要的事情。与官方文档相反,特定于功能的范围层次结构如下:

      1. 无名(声明的参数)
      2. 本地
      3. 参数

【问题讨论】:

    标签: function coldfusion scope arguments user-defined-functions


    【解决方案1】:

    在 ColdFusion 中,所有参数都在每个函数开头的未命名函数局部范围内重复。这段代码:

    <cfset writeOutput("myArg still exists, and evaluates to: " & myArg)>
    

    不是访问参数范围,而是访问函数本地范围。如果您更改了代码以访问参数范围,那么不出所料,您将看到该变量不再存在。

    顺便说一句,Railo 的行为并非如此。

    【讨论】:

    • 函数本地!=本地?我尝试测试并在本地范围内删除以防万一,它仍在输出“foobar”
    • 不,又不一样了。 Adobe 在这方面有点加强了他们对本地范围的实施。我写了一篇博客文章,涉及到这一点……我现在在火车上,我正在打电话,所以现在不能把它挖出来,但是当我进入办公室时会这样做。
    • 我的示例代码确实表明已删除的参数不再在参数范围内。关键是要证明它仍然在其他地方定义。我似乎记得在某处(可能是您的文章)读到 CF 保留了一些奇怪的 CF9 之前的无名 var 范围的残余物。这就是我们正在处理的事情吗?如果是这样,它需要一个能够将其与“现代”本地范围区分开来的名称。我称它为“声明的参数范围”,因为这似乎是唯一可以驻留在那里的变量。我仍然想知道是否可以明确引用它(我猜不是)。
    【解决方案2】:

    有趣的是,这个测试用例有一个非常奇怪的行为。我不知道为什么myArg 仍然可用。但是,如果您确定 var 的范围并执行此操作:

    <cfset writeOutput("myArg still exists, and evaluates to: " & arguments.myArg)>
    

    或者如果不是structDelete(),你将它设置为null

    <cfset myArg = javacast("null","")>
    

    然后你会得到"myArg no longer exists"

    这可能是 Adob​​e CF 优化的边缘案例。 Railo 按预期运行并获得预期结果。你可以在http://cflive.net/自己测试一下

    【讨论】:

    • 在声明的参数上设置值时,它似乎适用于它的两个实例。因此,将其值设置为 null 将摆脱这两个版本有点“有意义”。克服不可删除参数问题的好方法。但我仍然想知道是否有任何方法可以利用这种奇怪。
    • Railo 太无聊了——它几乎不会让你感到惊讶 :) 我想如果这种行为不是 CFML 规范的一部分,最好不要编写依赖它的代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-15
    • 1970-01-01
    • 2012-05-25
    • 2018-06-05
    • 2021-12-27
    • 1970-01-01
    相关资源
    最近更新 更多