4

在我被要求研究冷融合应用程序中一些奇怪的间歇性错误之前,我没有使用过冷融合。

在阅读了范围后,我认为问题是因为我的 cfc 函数中的变量都没有使用var关键字,并且在各种函数中使用了相同的变量名。因此,据我了解,变量的范围是页面级别,调用这些函数的不同线程将覆盖导致“奇怪”问题的变量。

我的问题是这样做的正确方法是什么?

 <cfset var listCount = 0>
 <cfquery name="qGetElementsByType" dbtype="query" maxrows="#arguments.num_to_return#">
    SELECT elementId,
           title, PIhtml, Rerhtml,
           text, url, image, Rank, isPoll, pollId, subjectId
    FROM   arguments.element_query
    WHERE  <cfloop list="#arguments.element_type_id#" index="lcv">
               <cfif listCount GT 0>
                  OR
               </cfif>
               subjectid =  #lcv#
              <cfset listCount = listCount + 1>
           </cfloop>
</cfquery>

是否var需要在每次设置 listCount 变量时添加,还是仅在初始声明时添加?

4

3 回答 3

10

(我希望这个答案不会太啰嗦。我认为现有的答案没有提供足够的信息,但希望没有走得太远……)


在 CF 中,有各种各样的范围可以放置变量(应用程序、会话、url、cgi 等)。

其中一些需要使用显式声明(例如,会话变量必须始终具有范围),其他可以在读取变量时自动访问(例如,可以使用无范围变量读取表单和 url 变量) - 有优先顺序这里决定了在哪些范围内检查无范围的变量。

此排序中的底部范围是variables范围,它是适用于整个当前页面/对象实例的范围。

设置新变量时,如果没有作用域,则在作用域中创建它variables。由于这是一个全局范围,因此可以从同一函数的不同实例以及不同的函数访问它,这会导致您意识到的问题。


为了防止变量进入全局变量范围,您必须将它放在函数的local范围内。(从技术上讲,您可以将它放在函数的arguments范围内,但这可能会使人们感到困惑。)

在早期版本的 CF 中,无法显式访问本地范围 - 您需要使用var关键字才能在本地范围内创建变量 - 并且一旦创建,它将始终优先(无论是读取还是写入)变量范围。

使用 CF9,local范围现在是“正确”范围并且可以显式访问,因此<cfset var x = 0 />您可以编写而不是使用<cfset local.x = 0 />- 这样做的主要好处是当您创建var无法使用关键字的变量时,例如<cfquery name="local.qGetElementsByType" ...><cfloop index="local.lcv"...>

您仍然只需要在第一次创建每个变量时应用本地范围,以防止它进入变量范围 - 如果您愿意,后续读取/更新可以是无范围的,就像在执行 var 范围时一样。
(尽管无作用域的变量还有其他潜在的作用域相关问题,例如在<cfloop query="queryname">块内部,因此有些人会争辩说无论如何你都应该对所有变量进行作用域。)


总之,为了使您显示的代码安全,您需要确定以下范围:

  • qGetElementsByType来自 cfquery 标记
  • lvc来自 cfloop 标签

由于这些变量不是使用 cfset 创建的,因此最容易通过在名称前加上前缀来完成范围界定local.

由于您已经var确定了 listCount 变量的范围,因此您不需要在同一个函数中再次执行此操作 - 您可以选择使用<cfset local.listCount = local.listCount + 1>(或确实是<cfset local.listCount++ >),但这也是一个偏好问题,不需要防止泄漏到变量范围内.

(旁注:理想情况下,您应该使用 cfqueryparam 标记#lcv#来防止 SQL 注入 - 即使这是一个查询查询,这可能仍然是一个问题,并且在安全性方面始终保持安全总是更好。)

当然,这只是这个函数——你还需要修复其他函数——一个简单的方法是使用varscoper工具扫描你的整个代码库并识别需要作用域的变量。

于 2012-06-10T20:09:26.280 回答
2

除了 Evik 在他的回答中所说的之外,您还应该使用VAR 所有的函数局部变量。 qGetElementsByType并且也lcv应该是 VARed。如果您使用的是 CF9 及更高版本,您可以简单地使用范围来确定它们的LOCAL范围,例如:local.qGetElementsByType等。

于 2012-06-10T19:19:40.923 回答
0

我假设您的问题专门针对这一行:

<cfset listCount = listCount + 1>

不,您不需要在此行中再次使用 var。

但是,如果稍后在页面中,您尝试使用访问名为 listCount 的变量,它将已经具有您刚刚运行的代码中的值,因此您需要重新创建它。

于 2012-06-10T19:06:03.920 回答