コールドフュージョン:CFC で変数キーワードを省略しても安全ですか?
-
09-06-2019 - |
質問
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") は "私は持っています 引数 そして 関数ローカル変数"
doAnotherThing("args") は "私は持っています 変数のプライベートインスタンス そして 関数ローカル変数."
他のヒント
はいと言います。それは明示的に必要ですか?いいえ。やらずに済むでしょうか?もちろん。トラブルを求めているのですか?絶対に。cffunction 内に次のものがあるとします。
<cfset foo = "bar" />
これにより、その変数は関数のローカル var スコープに配置されず、CFC のグローバル VARIABLES スコープに配置されます。これは、その CFC のすべてのメソッドで使用できることを意味します。これを実行したい場合もありますが、ほとんどの場合は競合状態を要求することになります。
サーバーによって変数が読み取られているときに、その変数がスコープ (REQUEST.、SESSION. など) の一部として明示的に宣言されていない場合、ColdFusion は ScopeCheck() を実行して、変数がどのスコープにあるかを判断します。これにより、アプリケーション サーバーに不要なオーバーヘッドがかかるだけでなく、変数が 1 つのスコープ内にあるにもかかわらず、ScopeCheck() が優先順位の高い同じ名前の変数を見つけてしまうハイジャックの可能性も生じます。
常に、常に、常に、すべての変数のスコープを設定します。どんなに些細なことでも構いません。クエリ名やループインデックスなども同様です。あなた自身とあなたの後に続く人々を痛みから救いましょう。
特に CFC では、適切な範囲設定が重要です。余分な「冗長さ」には、明確さの価値があります。変数が意図された範囲から外れると、重大な問題が発生し、診断が非常に困難になります。
冗長であることは必ずしも悪いことではありません。関数とメソッドには、gau() ではなく getAuthenticatedUser() のようなわかりやすい名前を付けます。データベースの列とテーブルは、empprl ではなく EmployeePayroll のように説明的なままにするのが最善です。したがって、短期記憶がプロジェクトの詳細でいっぱいになっているときは、簡潔にするほうが「簡単」かもしれませんが、説明的であることは意図を示しており、短期記憶が他のことでいっぱいになってからずっと後の、アプリケーションのメンテナンス段階で役に立ちます。 。
あなたの質問に対する簡単な答えは、「いいえ、おそらくそれを試みても問題に遭遇することはないだろう」です。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" />
次に、その変数を var スコープに入れるように CF に指示します。
状況を少し複雑にするのは、次のようなときに問題 (予期しないときに変数値が変化する) に遭遇する可能性があることです。 ない インライン UDF で var スコープを使用します。
したがって、経験則は常に、常に、常に、です。 いつも var-scope 関数内部変数 (クエリ名を含む)。というツールがあります varScoper これは、var スコープが必要な変数を見つけるのに役立ちます。最後に確認したところ、完璧ではありませんでしたが、間違いなく始まりです。
ただし、それは 悪い CFC または標準 CFM ページでスコープなしで変数を参照 (表示/使用) するアイデア (読み取りスコープを指定できないため、var スコープの変数は当然除きます)。CF7 の時点では、スコープを指定せずに変数を読み取ると、最初に一致したものが優先される、特定の順序でチェックされるスコープが 9 つありました。CF8 では、そのリストにはさらに多くのスコープがある可能性がありますが、私は確認していません。これを行うと、あるスコープから値を期待しているときに、別のスコープから値を取得してしまう危険性があります。デバッグするのは悪夢です...確かに。;)
つまり、要するに: 暗示する 変数のスコープ (セット上) は、ひどいアイデアではありません (とにかく、通常は指定しますが)。しかし 推測する 変数のスコープ (読み取り時) が問題を引き起こしています。
変数スコープ内で明示的にスコープを設定しないことは機能する可能性がありますが、それは良いアイデアではなく、正直なところ、これが唯一の理由です ない 私の怠惰からです。すべてを明示的にスコープすると、1) 潜在的な問題が回避され、2) 内容がどのスコープに含まれるか疑問がなくなるため、コードが読みやすくなります。
私にとって、これによってコードが冗長になるわけではありません (もちろん、不必要に冗長になるわけでもありません)。実際に読みやすくなり、混乱が避けられ、明示的にスコープを設定しない場合に発生する可能性のある奇妙な副作用が回避されます。
あなたの質問に対する簡単な答えは次のとおりです。「いいえ、その必要はありません」
ただし、実際には、これらの変数にアクセスするときに変数識別子を使用することがベスト プラクティスとして推奨されると思います。私の意見では、将来あなたのコードに遭遇し、関数の途中を見ている人は、ローカル関数の関数の先頭をスキャンすることなく、変数のスコープを即座に知ることができるでしょう。
実際、ローカル構造体を 1 つ作成することで、CFC UDF に少し冗長性を追加しています。
<cfset var local = structNew() />
次に、すべてのローカル変数をその構造体に入れて参照するので、コードは次のようになります。
<cfset local.foo = 変数.bar + 10 />
あなたの回答を読んだ後、私は次のように考えています。
はい、安全です。一般に、変数のスコープを明示的に指定する必要はなく、また有用でもありません。すでに冗長な言語がさらに乱雑になるだけです。
確かに、小さな例外が 1 つあります。 ソルダーナル 変数スコープ変数の修飾が必要な場合に指摘されています。それは、同じ名前の関数ローカル変数がある場合です。(しかし、とにかくそうすべきではないでしょう。)
ベストプラクティスはさておき、CFC にアクセスする方法にも依存する可能性があると思いますが、オブジェクトを作成して ColdFusion からアクセスするときに CFC を省略しても問題はありませんでした。ただし、フレックス/フラッシュのアクションスクリプトを介してリモートでアクセスしたりマッピングしたりするときに必要になる可能性があると思います。
ここはとても良いものです CFC スコープのリファレンス レイモンド・カムデンより。個人的には、混乱を避けるために 'self' ハッシュを作成することを好みます (関数内で 'variables' スコープを使用していないことに注意してください)。
<cfcomponent>
<cfset variables.self = structNew()>
<cfscript>
structInsert(variables.self, <key>, <value>);
...
</cfscript>
<cffunction name="foo">
self.<key> = <value>
<cfreturn self.<key> />
</cffunction>
...