设置变量时,ColdFusion中的范围求值顺序是什么?

设置变量时,ColdFusion中的范围求值顺序是什么?,coldfusion,coldfusion-9,Coldfusion,Coldfusion 9,在以下情况下,范围评估顺序是众所周知的/记录在案的。但是,在设置变量时,我找不到有关范围求值顺序的任何信息 人们可能会认为这是相同的列表,但这里似乎有一些警告: <cfset qryChain = queryNew("id,next")> <!--- add some data so the cfloop kicks in ---> <cfloop query="qryChain"> <cfset Next = StructNew()>

在以下情况下,范围评估顺序是众所周知的/记录在案的。但是,在设置变量时,我找不到有关范围求值顺序的任何信息

人们可能会认为这是相同的列表,但这里似乎有一些警告:

<cfset qryChain = queryNew("id,next")>
<!--- add some data so the cfloop kicks in --->
<cfloop query="qryChain">
    <cfset Next = StructNew()>
    <cfset Next.id = qryChain.next>
</cfloop>

上面的代码试图重用不应该重用的变量名,但以意外的方式失败

由于
cfset
s位于查询循环内,因此范围评估顺序的第4项应同时用于这两个循环。相反,
Next
被评估为
变量。Next
(项目6),然后
Next.id
被评估为
变量。qryChain.Next.id
(项目4)并失败


这有文件记录吗?这仅仅是上面“使用”列表中的第1-6项,还有一些注意事项吗?这些警告是故意的还是错误的?还有什么其他注意事项吗?

您可能会遇到此错误(因为这是我收到的错误):

这是因为当您在查询的cfloop中时,在计算无范围变量时,查询范围优先于变量范围。但是,当您分配范围较少的变量(在cfloop查询上下文中或不在cfloop查询上下文中)时,则使用
变量
范围。所以当你分配

<cfset Next = StructNew()>
现在,您将从查询范围中获取
Next
(由于查询范围中的Next不是一个结构,因此您将得到一个错误)


因此,为了回答您的主要问题-当您分配一个没有指定范围的变量时,CF将把该变量放入
变量
范围。当您尝试计算未指定范围的变量时,它将使用查找匹配项(在本例中,在
查询
范围中查找匹配项)。

我想我理解这里发生的事情。您看到的行为来自访问变量以设置变量时的范围搜索。当设置变量而不确定其作用域时,ColdFusion将首先搜索作用域以查看该变量是否存在于任何位置,如果存在,则将在该位置设置该变量

在您的第一个示例中:

<cfset qryChain = queryNew("id,next")>
    <!--- add some data so the cfloop kicks in --->
<cfloop query="qryChain">
    <cfset Next = StructNew()>
    <cfset Next.id = qryChain.next>
</cfloop>

当您创建“下一个”变量时,实际上是将该变量放入变量范围,您可以证明,如果您在循环过程中的任何时候转储变量范围。您将看到一个带有空结构的“下一个变量”

问题在下一行。当您尝试访问下一个变量以向其中设置新键时,ColdFusion首先查找查询结果中存在的下一个变量,因为在循环查询时,查询范围(实际上不是范围,但在本例中它的工作方式与范围类似)的优先级高于变量范围。该变量不包含结构,因此您将得到一个关于如何引用它的错误

范围搜索正在发生,但实际上并不是在设置时,而是在访问以便设置时

下面是一个工作示例来演示这一点

<cfset qryChain = queryNew("id,next")>
<cfset queryAddRow(qryChain, 3) />
<cfdump var="#qryChain#">
<!--- add some data so the cfloop kicks in --->
<cfloop query="qryChain">
    <cfset Next = StructNew()>
    <cfdump var="#variables#">
    <cfset Next.id = qryChain.next>
    <cfdump var="#qryChain#">

</cfloop>

在本例中,我展示了在创建下一个变量后,它确实存在于variables作用域中,但是当您立即尝试在其中设置一个键而不进行访问时,您将从查询中的当前记录中获取下一个变量。发生这种情况的唯一原因是查询碰巧有一个列名与您尝试使用的变量匹配的记录

那么为什么ColdFusion不尝试将StructNew()设置到查询范围(伪范围)中呢?无法使用点表示法操作查询。同样,这不是一个真正的范围。因此,从这个意义上讲,它是只读的,并且被跳过 要在CF中操作查询结果集,必须使用查询函数variables scope。因为非范围变量总是放在变量范围内。然而,在您尝试设置id的行中,还有另一个在后台进行的阶段,它需要首先以读取容量访问变量,然后尝试执行设置。在这种情况下,它确实会在查询中找到下一个变量,因为范围搜索将首先发生,以确定在下一个exists中将该键设置为,然后当您尝试将某项设置为该键时,它将失败

至于您的第二组示例,这是预期的行为,很容易解释

在第一个示例中,您正在改变变量(将其放置在局部范围内)。然后设置该变量的值。当您为一个变量设置一个值时(不确定其作用域),ColdFusion会检查该变量是否已经存在于任何地方(因此它进行范围搜索,这也是在此时访问,而不是设置),它会在本地范围中找到该变量,然后在那里设置该值。然后再次设置该值,这一次正确地确定其范围,因此不进行搜索

在第二个示例中,您在初始设置变量时没有对其进行变量更改,它不存在于任何位置,因此它被设置为变量范围。如果它已经存在于局部范围中,那么ColdFusion会找到它并将其设置在那里(如第一个示例中所示),但是由于它不存在,并且它不是var,所以它被设置为variables范围

最后,在上一个示例中,您显式地确定了变量的作用域,因此它将在局部作用域中设置。然后重新设置,但不确定其范围。ColdFusion将在本地范围内找到它并覆盖它


这个故事的寓意是,确定变量的范围。我认为获得预期的行为很重要。范围搜索从来都不是一个好主意,但不幸的是,它一直存在。如果您了解范围搜索的工作方式,我在这里看不到任何我称之为bug的东西,甚至不可预测的行为。

在分配过程中进行范围评估

我知道在ColdFusion中创建变量时有两种不同的范围评估方法。我还没有测试过e
<cfset qryChain = queryNew("id,next")>
    <!--- add some data so the cfloop kicks in --->
<cfloop query="qryChain">
    <cfset Next = StructNew()>
    <cfset Next.id = qryChain.next>
</cfloop>
<cfset qryChain = queryNew("id,next")>
<cfset queryAddRow(qryChain, 3) />
<cfdump var="#qryChain#">
<!--- add some data so the cfloop kicks in --->
<cfloop query="qryChain">
    <cfset Next = StructNew()>
    <cfdump var="#variables#">
    <cfset Next.id = qryChain.next>
    <cfdump var="#qryChain#">

</cfloop>
<!--- sets variables in 1 scope --->
<cfscript>
    var x = 0;
    x = 1;
    local.x = 7;
</cfscript>
<!--- sets variables in 2 scopes --->
<cfscript>
    x = 1;
    var x = 0;
    local.x = 7;
</cfscript>
<cfset var localVars = StructNew()>
<cfset localVars.x = 7>
<cfset localVars.y = 1>