ColdFusion:在CFC中保留变量关键字是否安全?

时间:2020-03-05 18:52:20  来源:igfitidea点击:

在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>

解决方案

回答

创建变量时,不必指定"变量",因为默认情况下,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")返回"我有一个变量的私有实例和一个函数局部变量。"

回答

对问题的简短回答是,不,尝试这样做可能不会遇到麻烦。在UDF的上下文之外(甚至仍在CFC中),无范围的set语句表示变量的作用域。

此外,在CFC中,变量作用域可用于其所有功能。它类似于该" 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作用域检查的变量。最后我检查了一下它是否完美,但这绝对是一个开始。

但是,在CFC甚至标准CFM页面中引用(显示/使用)没有范围的变量(显然是可变范围变量,因为我们无法指定要读取的范围)是一个坏主意。从CF7开始,当我们在不指定作用域的情况下读取变量时,将按照特定顺序检查9个作用域,先赢。使用CF8时,该列表中可能会有更多作用域,我没有检查过。当执行此操作时,冒着从一个范围获得值的风险,而从另一个范围获得了期望的值;这是调试的噩梦...向我们保证。 ;)

简而言之:暗示变量的作用域(在集合中)并不是一个糟糕的主意(尽管我通常还是会指定它);但是推断变量的作用域(读取时)会带来麻烦。

回答

阅读答案后,这就是我的想法:

是的,这很安全。通常,没有必要或者没有必要明确指定变量范围。它只是给已经很冗长的语言增加了混乱。

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

回答

我们问题的简单答案是:
"不,没有必要"

但是,我认为最佳实践建议我们在访问这些变量时确实使用变量标识符。在我看来,将来在代码中出现并正在某个函数中间的任何人都将立即知道该变量的作用域,而不必扫描局部函数的顶部。

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

<cfset var local = structNew()/>

然后,我将所有本地var放入该结构中,并以这种方式引用它们,这样我的代码将如下所示:

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

回答

特别是在氟氯化碳中,适当的范围界定很重要。额外的"冗长性"值得澄清。
变量超出其预期范围会导致严重问题,并且非常难以诊断。

详尽并不总是一件坏事。我们以描述性方式(例如getAuthenticatedUser()而不是gau())来命名函数和方法。数据库列和表最好像EmployeePayroll那样保留描述性,而不是empprl。因此,当短期记忆中充满了项目详细信息时,保持简洁可能会"更轻松",但是在短期记忆中充满其他东西很长时间之后,进行描述性说明可以表明意图并在应用程序的维护阶段会有所帮助。

回答

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

回答

我会说是的。明确有必要吗?没有。我们可以不这样做而逃脱吗?当然。你在找麻烦吗?绝对地。如果cffunction中包含以下内容:

<cfset foo = "bar" />

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

服务器读取任何变量时,如果未明确将该变量声明为作用域的一部分(REQUEST。,SESSION等),则ColdFusion将运行ScopeCheck()以确定该变量位于哪个作用域。这给应用程序服务器带来了不必要的开销,它还引入了劫持功能,即变量位于一个作用域中,但是ScopeCheck()发现同名变量的优先级更高。

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

回答

这是雷蒙德·卡姆登(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>

  ...

回答

没有明确定义变量范围可能会起作用,但这不是一个好主意,老实说,不这样做的唯一原因是出于对IMO懒惰的考虑。如果我们明确规定了所有范围,则1)可以避免潜在的问题,2)可以使代码更易于阅读,因为毫无疑问,范围是什么。

对我而言,它不会使代码变得更加冗长(当然也不会不必要地冗长),实际上,它更易于阅读,避免混淆,并且避免了怪异的副作用(如果我们未明确限制范围的话)。