在我被要求在冷敷应用程序中查看一些奇怪的间歇性错误之前,没有使用过coldfusion。
在阅读了范围后,我认为问题是因为我的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>
每次设置listCount变量时,还是只需要在初始声明时添加var
?
答案 0 :(得分:9)
(我希望这个答案不会太冗长。我不认为现有的答案提供了足够的信息,但希望在其他方面没有走得太远......)
在CF中,有各种范围可以放置变量(application,session,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"...>
在第一次创建每个变量时,你仍然只需要需要来应用本地范围,以防止它进入变量范围 - 如果你愿意,后续的读取/更新可以是无范围的,就像它们一样在做范围时。
(虽然与未编码变量存在其他潜在的与范围相关的问题,例如<cfloop query="queryname">
块内部,因此有些人会争辩说,无论如何都应该始终确定所有变量的范围。)
总之,要使您显示的代码安全,您需要确定范围:
qGetElementsByType
lvc
由于这些变量不是使用cfset创建的,因此最简单的方法是使用local.
由于您已经var
确定了listCount变量的范围,因此您不需要在同一个函数中再次执行此操作 - 您可以选择使用<cfset local.listCount = local.listCount + 1>
(或确实<cfset local.listCount++ >
)但是这是一个偏好问题,不需要防止泄漏到变量范围。
(旁注:理想情况下,您应该使用#lcv#
周围的cfqueryparam标记来防止SQL注入 - 即使这是查询查询,这可能仍然是一个问题,并且最好安全地发挥它关于安全。)
当然,这就是这个功能 - 你还需要修复其他功能 - 一个简单的方法是使用 varscoper 工具扫描你的整个代码库并确定需要确定范围的变量。
答案 1 :(得分:2)
除了Evik在他的回答中所说的,你应该VAR
所有你的函数局部变量。 qGetElementsByType
和lcv
也应该是VARed。如果您使用的是CF9,则只需使用LOCAL
范围对其进行范围调整,例如:local.qGetElementsByType
等。
答案 2 :(得分:0)
我假设你的问题专门针对这一行:
<cfset listCount = listCount + 1>
不,你不需要在这一行再次使用var。
但是,如果在页面的后面,您尝试使用名为listCount的变量访问它,它将具有您刚刚运行的代码中的值,因此您需要重新创建它。