5

在 ColdFusion 组件 (CFC) 中,是否有必要为变量范围的变量使用完全限定名称?

如果我改变这个,我会不会惹上麻烦:

<cfcomponent>
    <cfset variables.foo = "a private instance variable">

    <cffunction name = "doSomething">
        <cfset var bar = "a function local variable">
        <cfreturn "I have #variables.foo# and #bar#.">
    </cffunction>
</cfcomponent>

到这个?

<cfcomponent>
    <cfset foo = "a private instance variable">

    <cffunction name = "doSomething">
        <cfset var bar = "a function local variable">
        <cfreturn "I have #foo# and #bar#.">
    </cffunction>
</cfcomponent>
4

9 回答 9

10

创建变量时指定“变量”无关紧要,因为 foo 默认会放在变量范围内;但是当您访问变量时会很重要。

<cfcomponent>
    <cfset foo = "a private instance variable">

    <cffunction name="doSomething">
        <cfargument name="foo" required="yes"/>
        <cfset var bar = "a function local variable">
        <cfreturn "I have #foo# and #bar#.">
    </cffunction>

    <cffunction name="doAnotherThing">
        <cfargument name="foo" required="yes"/>
        <cfset var bar = "a function local variable">
        <cfreturn "I have #variables.foo# and #bar#.">
    </cffunction>

</cfcomponent>

doSomething("args") 返回“我有args和一个函数局部变量

doAnotherThing("args") 返回“我有一个变量的私有实例和一个函数局部变量。”

于 2008-09-12T17:22:31.873 回答
6

我会说是的。有明确的必要吗?没有。你能不做就逃脱吗?当然。你是在自找麻烦吗?绝对地。如果您在 cffunction 中有以下内容:

<cfset foo = "bar" />

这不会将该变量放在函数 local var 范围内,而是将其放在 CFC 的全局 VARIABLES 范围内,这意味着它可用于该 CFC 的每个方法。有时您可能想要这样做,但大多数时候您会要求竞争条件。

当服务器正在读取任何变量时,如果该变量未明确声明为范围的一部分(REQUEST.、SESSION.等),则 ColdFusion 将运行 ScopeCheck() 来确定变量所在的范围。不仅这是否会给您的应用程序服务器带来不必要的开销,它还引入了劫持的能力,即您的变量在一个范围内,但是 ScopeCheck() 发现了一个同名的变量在优先级顺序中更高。

总是,总是,总是,范围所有变量。不管多么琐碎。甚至查询名称和循环索引之类的东西。从痛苦中拯救你自己,以及那些在你身后的人。

于 2008-09-24T18:14:17.897 回答
5

特别是在 CFC 中,适当的范围界定很重要。额外的“冗长”值得清晰。让变量滑出它们的预定范围会导致严重的问题并且很难诊断。

冗长并不总是一件坏事。我们以描述性方式命名我们的函数和方法,例如 getAuthenticatedUser(),而不是 gau()。数据库列和表最好保留描述性,如 EmployeePayroll 而不是 empprl。因此,当您的短期记忆中充满项目细节时,简洁可能会“更容易”,但描述性表明您的意图并且在应用程序的维护阶段很有帮助,在您的短期记忆已经充满其他东西很久之后.

于 2008-09-15T17:52:33.993 回答
3

对您的问题的简短回答是,不,您可能不会在尝试这样做时遇到麻烦。在 UDF 的上下文之外(甚至还在 CFC 内部),一个未限定范围的 set 语句意味着变量范围。

此外,在 CFC 中,Variables 范围可用于其所有功能;它是该 CFC 中的全局范围——类似于“this”范围,除了变量范围类似于“私有”变量,而 this 范围类似于公共变量。

要对此进行测试,请创建 test.cfc:

<cfcomponent>
    <cfset foo = "bar" />
    <cffunction name="dumpit" output="true">
        <cfdump var="#variables#" label="cfc variables scope">
        <cfdump var="#this#" label="cfc this scope">
    </cffunction>
</cfcomponent>

和一个测试它的页面,test.cfm:

<cfset createObject("component", "test").dumpit() />

结果将是:


现在,为了解决我在您的示例代码中看到的另一个问题......

在 CF 中,所有用户定义函数都有一个特殊的未命名范围,通常称为“var”范围。如果您在 UDF 中执行以下操作:

<cfset foo = "bar" />

然后你告诉 CF 将该变量放入 var 范围。

更复杂的是,当您在内联 UDF中使用 var 范围时,您可能会遇到问题(变量值在您不期望的情况下发生变化) 。

因此,经验法则是始终、始终、始终、始终var-scope 您的函数内部变量(包括查询名称)。有一个名为varScoper的工具可以帮助您找到需要 var-scoped 的变量。最后我检查了它并不完美,但这绝对是一个开始。

但是,在 CFC 甚至标准 CFM 页面中引用(显示/使用)没有范围的变量(显然 var 范围的变量除外,因为您无法指定要读取的范围)是一个坏主意。从 CF7 开始,当您在未指定范围的情况下读取变量时,按特定顺序检查了 9 个范围,首先匹配获胜。使用 CF8,该列表中可能有更多范围,我尚未检查。当你这样做时,当你期望从另一个范围获得价值时,你会冒着从另一个范围获得价值的风险。这是调试的噩梦......我向你保证。;)

所以简而言之:暗示一个变量的范围(在集合上)并不是一个糟糕的主意(尽管我通常会指定它);但是推断变量的范围(在读取时)是自找麻烦。

于 2008-09-12T17:27:14.343 回答
2

在变量范围内不明确地确定范围可能有效,但这不是一个好主意,老实说,唯一这样做的原因是 IMO 的懒惰。如果您明确地确定所有内容的范围 1) 您可以避免潜在的问题,并且 2) 它使代码更易于阅读,因为毫无疑问事物在哪个范围内。

对我来说,它不会使代码更冗长(当然也不是不必要的冗长)——它实际上更容易阅读,避免混淆,并避免如果你没有明确范围,可能会出现奇怪的副作用。

于 2008-09-29T12:04:25.797 回答
1

您的问题的简单答案是:“不,没有必要”

但是,我认为最佳实践会建议您实际上在访问这些变量时使用变量标识符。在我看来,任何将来遇到您的代码并且正在查看函数中间的人都会立即知道变量的范围,而无需扫描函数顶部的局部函数。

事实上,我通过创建一个本地结构为我的 CFC UDF 添加了一些额外的详细信息:

<cfset var local = structNew() />

然后我把我所有的本地变量放在那个结构中并以这种方式引用它们,所以我的代码看起来像这样:

<cfset local.foo = variables.bar + 10 />

于 2008-09-15T13:44:20.890 回答
0

看完你的回答后,我的想法是:

是的,它是安全的。一般来说,明确指定变量范围是没有必要或有用的。它只是给已经冗长的语言增加了混乱。

诚然,正如Soldarnal指出的那样,有一个小例外,需要限定变量范围的变量。也就是说,如果您有一个同名的函数局部变量。(但你可能无论如何都不应该这样做。)

于 2008-09-12T20:38:06.553 回答
0

除了最佳实践之外,我相信它还可能取决于您将如何访问您的 cfc,在创建对象和从冷融合访问它们时将它们排除在外没有任何问题。但是我认为在通过 flex/flash 中的 actionscript 远程访问和/或映射它们时可能需要它。

于 2008-09-19T03:21:53.927 回答
0

这是 Raymond Camden 提供的非常好的CFC 范围参考。就个人而言,我更喜欢创建一个“自我”哈希以避免所有混淆(注意我不在函数中使用“变量”范围):

<cfcomponent>
  <cfset variables.self = structNew()>
  <cfscript>
    structInsert(variables.self, <key>, <value>);
    ...
  </cfscript>

  <cffunction name="foo">
    self.<key> = <value>
    <cfreturn self.<key> />
  </cffunction>

  ...
于 2008-09-25T02:16:37.220 回答