【VBA】変数の適用範囲(スコープ)を理解する

アイキャッチ VBA

こちらの記事(VBAの変数宣言について)では、変数宣言を行う3つの目的のうち、次の2点について解説しました。

  1. 変数名(解説済み)
  2. 変数のデータ型(解説済み)

今回は、残りの3点目である「変数の適用範囲(スコープ)」について解説します。
変数を正しく使いこなすうえで非常に重要なポイントですので、ぜひ押さえておきましょう。

変数の適用範囲(スコープ)とは

VBAでは、変数をどこで・どのように宣言するかによって、その変数の使える範囲が決まります。
この「使える範囲」のことを「適用範囲(スコープ)」と呼びます。

変数は「入れ物」ということで、イメージしやすいように身近な例に置き換えてみます。

変数をロッカーや倉庫に例えると…
  • 部屋の中にあるロッカー…その部屋にいる人だけが使える
    プロシージャ内変数(ローカル変数)
  • 建物全体にある共有ロッカー…建物内のどこからでも使える
    モジュールレベル変数(モジュール全体で有効)
  • 町全体にある倉庫…町のどこからでも使える
    グローバル変数(プロジェクト全体で有効)

このように、変数の「置き場所(宣言場所)」と「宣言のステートメント」によって、使える範囲が変わるのです。
なお、モジュールプロシージャといったVBAの用語については、こちら↓の記事で詳しく解説していますので、参考にしてみてください。

適用範囲(スコープ)の種類と宣言ステートメント

こちらの記事(VBAの変数宣言について)では「変数宣言はDimステートメントを使う」という説明を行っています。もちろんDimステートメントは最も基本的で使用頻度の高い宣言ステートメントですが、実は宣言ステートメントはDimだけではありません

宣言場所によって、使えるステートメントは以下のとおりです。

宣言場所ステートメント
プロシージャ内Dimステートメント
Staticステートメント
宣言セクションPrivateステートメント
Dimステートメント
標準モジュールの宣言セクションPublicステートメント

それぞれ解説します。

プロシージャ内で宣言(Dim、Static)

プロシージャ内で変数宣言した変数を「プロシージャ内変数」といいます。

宣言場所

プロシージャ内(Private Sub ※※※ ~ End Subの間)にDimステートメント又はStaticステートメントを使い、変数宣言を行います。

適用範囲(スコープ)

プロシージャ内で宣言した変数の適用範囲は、そのプロシージャ内のみです。

プロシージャ内で宣言した変数の適用範囲

有効期間

変数の有効期間は、DimステートメントとStaticステートメントで異なります。

ステートメント有効期間
Dimステートメントプロシージャ終了後は破棄される
Staticステートメントプロシージャ終了後も値を保持

Dim ステートメントで宣言した変数は、プロシージャが終了(End Sub に到達)した時点で値がリセットされます。
一方、Static ステートメントで宣言した変数は、プロシージャ終了後もそのまま値を保持します。

以下のコードを例に、違いを確認してみましょう。

Sub Test()

 Dim MyID As String
 MyID = InputBox("IDを入力してください",,MyID)
 If MyID <> "" then
    MsgBox MyID & "さんが入力されました"
 End If

End Sub 

【Dimステートメントの場合】
コードを実行すると、InputBox 関数の入力ダイアログが表示されます。
たとえば「中田」と入力すると「中田さんが入力されました」というメッセージが表示されます。
再度コードを実行すると、同じように入力ダイアログが表示され、入力待機状態となります。

なお、InputBox 関数の引数に既定値として MyID 変数を指定していますが、Dim で宣言された変数はプロシージャ終了時に初期化されるため、ダイアログボックスには何も表示されません。

【Staticステートメントの場合】
3行目の変数宣言を Static に変更して実行してみましょう。
入力ダイアログに「中田」と入力すると、同じようにメッセージが表示されます。
再度コードを実行すると、ダイアログボックスの既定値に先ほど入力した「中田」が表示されます。

このように、Static で宣言した変数は、プロシージャ終了後も値を保持し続けることがわかります。

宣言セクション(Private、Dim)

宣言セクションで変数宣言した変数を「モジュールレベル変数」といいます。

宣言場所

宣言セクションでの変数宣言

宣言セクションは、VBEでモジュールの先頭に位置し、最初のプロシージャ(SubFunction)よりも前に記述される領域です(上図参照)

適用範囲(スコープ)

モジュールの先頭にDimPrivateで宣言すると、同じモジュール内のすべてのプロシージャから参照できます。

上記例では宣言セクションで変数mCountを宣言していますが、この変数はSub1及びSub2両方のプロシージャで有効です。Sub1実行で変数に1を格納し、Sub2実行でメッセージボックスに1を表示する処理となります。

有効期間

モジュールレベル変数の値は、プロシージャを抜けても保持され、Accessを終了するか、またはVBAプロジェクトがリセットされるまで有効です。

標準モジュールの宣言セクション(Public)

標準モジュールの宣言セクションにおいて、Publicを用いて変数宣言した変数を「グローバル変数」といいます。

宣言場所

標準モジュールの宣言セクションで変数宣言

前述した2つの宣言場所は、フォーム/レポートモジュールのプロシージャ内及び宣言セクションでしたが、こちらは標準モジュールの宣言セクションです

適用範囲(スコープ)

標準モジュールにPublicで宣言すると、プロジェクト全体(全てのモジュール)から利用できます

前述「宣言場所」で例示した図を解説すると、標準モジュールの宣言セクションで宣言した変数UserNameについて、モジュール①のプロシージャで文字列アクセス太郎を格納。モジュール②のプロシージャを実行すると、メッセージボックスにアクセス太郎が表示されます。

このように、どのモジュールからでも、変数の値にアクセスすることができます

有効期間

グローバル変数の値は、プロシージャを抜けても保持され、Accessを終了するか、またはVBAプロジェクトがリセットされるまで有効です。

モジュールレベル変数/グローバル変数の主な使用場面

値を保持し続けるモジュールレベル変数やグローバル変数は、使用に関するメリット/デメリットがあります。ここでは主な使用場面をご紹介します。

主な使用例

使用例内容
ログインユーザ情報ツール全体で使うユーザーID、ユーザー名、権限レベルなど。
どのフォーム・レポートからでも参照したい場合。
環境状態の一元管理たとえば「現在編集中の顧客ID」や「現在選択されている年度」など、
画面間をまたいで使うもの。
一時的なキャッシュ計算負荷の高いデータを一度取得して、複数のプロシージャで再利用
したい場合。

使用しない(プロシージャ内変数を使う)場面

内容
一時的にしか使わない値プロシージャ内で処理が完結する場合。プロシージャ内変数の使用が無難。
状態が頻繁に変わる値処理の途中で変数が書き換えられやすいため、追跡が難しくバグの原因
になりやすい。
モジュール間で複数人が
開発する場合
グローバル変数が多いと、誰がどこで使っているか分からなくなり、チーム
開発時に不具合が増える。

使用イメージ的には、以下の感覚で区別すると、自然にスコープ管理がしやすくなります

  • 「ツール全体の設定や環境」=グローバル/モジュールレベルでOK
  • 「処理に一時的に使うだけの値」=プロシージャ内変数

まとめ

今回の記事要点のまとめです

スコープとは
変数が「どこから参照できるか(使える範囲)」を指す概念。宣言場所と宣言方法によって変わる。

宣言ステートメントごとの違い
Dim:一般的な宣言。プロシージャ内ならローカル、モジュール先頭ならモジュールレベル
Static:プロシージャ内で使う宣言で、プロシージャを抜けても値を保持できる。
Private:モジュールレベル用。宣言したモジュール内でのみ有効。
Public:標準モジュールの宣言で使う。プロジェクト全体で変数を共有。

変数の使いどころ:モジュール/グローバル vs ローカル
<使ってよい場面>
ログインユーザ情報、環境設定、共通設定値など、複数モジュールからアクセスする必要がある値に対してはモジュールレベル/グローバル変数が有効。
<避けるべき場面>
単一プロシージャで完結する処理や、途中で値が変わりやすく追跡しにくい変数は、プロシージャ内変数を使うのが安全。グローバル変数を多用すると、どこで値を変更したか追いにくくなり、バグの原因になりやすい。

タイトルとURLをコピーしました