4

私は、coldfusion アプリケーションのいくつかの奇妙な断続的なバグを調査するように依頼される前に、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>

listCountvar変数が設定されるたびに追加する必要がありますか、それとも最初の宣言時にのみ追加する必要がありますか?

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">このため、何があっても常にすべての変数をスコープする必要があると主張する人もいます。)


要約すると、表示するコードを安全にするには、スコープを設定する必要があります。

  • qGetElementsByTypecfquery タグから
  • lvccfloop タグから

これらの変数は cfset で作成されないため、名前の前にlocal.

すでにvarlistCount 変数のスコープを設定しているため、同じ関数で再度行う必要はありません。オプションで<cfset local.listCount = local.listCount + 1>(または実際に<cfset local.listCount++ >は ) を使用できますが、これも好みの問題であり、変数スコープへのリークを防ぐために必要ではありません。 .

(補足: 理想的には、SQL インジェクションから保護するために cfqueryparam タグを使用する必要が#lcv#あります。これはクエリのクエリであるにもかかわらず、これは依然として問題になる可能性があり、セキュリティ上安全にプレイすることを常にお勧めします。)

もちろん、それはこの関数だけです。他の関数も修正する必要があります。これを行う簡単な方法は、varscoperツールを使用してコードベース全体をスキャンし、スコープが必要な変数を特定することです。

于 2012-06-10T20:09:26.280 に答える
2

Evik の答えに加えて、VAR すべての関数ローカル変数を使用する必要があります。 VAR も適用する必要がありますqGetElementsByTypelcvCF9 以降を使用している場合は、LOCALスコープを使用して簡単にスコープを設定できますlocal.qGetElementsByType

于 2012-06-10T19:19:40.923 に答える
0

あなたの質問は特にこの行に関するものだと思います:

<cfset listCount = listCount + 1>

いいえ、この行で再度 var を使用する必要はありません。

ただし、ページの後半で、listCount という名前の変数へのアクセスを使用しようとすると、実行したコードの値が既に含まれているため、再作成する必要があります。

于 2012-06-10T19:06:03.920 に答える