変数のスコープ
変数のスコープは、その変数が定義されたコンテキストです。ほとんどの PHP 変数は、スコープを1つだけ有しています。このスコープの範囲は、 includeやrequireにより読みこまれたファイルも含みます。例えば、
<?php$a = 1;include 'b.inc';?>
この例で、変数$a
はインクルードされた
b.inc
スクリプトの中でも利用可能です。しかし、
ユーザー定義の関数の中では変数の有効範囲はローカル関数の中となりま
す。関数の中で使用された変数はデフォルトで有効範囲が関数内部に制限
されます。例えば、
<?php$a = 1; /* グローバルスコープ */ function test(){ echo $a; /* ローカルスコープ変数の参照 */ } test();?>
このスクリプトは、出力を全く行いません。これは、echo 命令がローカ
ル版の $a
変数を参照しているにもかかわらず、こ
のスコープでは値が代入されていないからです。この動作は、特にローカ
ルな定義で上書きしない限りグローバル変数が自動的に関数で使用可能で
ある C 言語と少々異なっていると気がつかれるかもしれません。C言語の
ような場合、グローバル変数を不注意で変更してしまうという問題を生じ
る可能性があります。PHP では、グローバル変数は、関数の内部で使用す
る場合、関数の内部でグローバルとして宣言する必要があります。
global
キーワード
まず、global
の使用例を示します。
例1 global
の使用
<?php$a = 1;$b = 2;function Sum() { global $a, $b; $b = $a + $b;} Sum();echo $b;?>
上のスクリプトは、3
を出力します。関数の内部で
$a
、$b
をグローバル宣言を行うことにより、両変数への参照は、グローバル変数
の方を参照することになります。ある関数により操作できるグローバル変
数の数は無制限です。
グローバルスコープから変数をアクセスする2番目の方法は、PHPが定義す
る配列$GLOBALS
を使用することです。先の例は、次
のように書き換えることができます。
例2 globalのかわりに$GLOBALS
を使用する
<?php$a = 1;$b = 2;function Sum() { $GLOBALS['b'] = $GLOBALS['a'] + $GLOBALS['b'];} Sum();echo $b;?>
配列$GLOBALS
は連想配列であり、グローバル変数の
名前がキー、その変数の内容が配列要素の値となっています。
$GLOBALS
は スーパーグローバル
であるため、$GLOBALS
は全てのスコープに存在します。
以下にスーパーグローバルの効果を示す例を示します。
例3 スーパーグローバルとスコープの例
<?phpfunction test_superglobal(){ echo $_POST['name'];}?>
注意:
global
キーワードを関数の外部で使ってもエラーにはなりません。 そのファイルが関数の内部からインクルードされたときに使うことができます。
静的変数の使用
変数のスコープに関する別の重要な機能は、静的 (static) 変数です。静的変数はローカル関数スコープのみに 存在しますが、プログラム実行がこのスコープの外で行われるようになっ てもその値を失わないません。次の例を見てください。
例4 静的変数が必要な場面の例
<?phpfunction test(){ $a = 0; echo $a; $a++;}?>
この関数は、コールされる度に$a
を
0
にセットし、0
を出力するのでほとん
ど役にたちません。変数を1増やす $a++ は、関数から外に出ると変数
$a
が消えてしまうために目的を達成しません。現在
のカウントの追跡ができるようにカウント関数を使用できるようにするた
めには、変数$a
をstaticとして宣言します。
例5 静的変数の使用例
<?phpfunction test(){ static $a = 0; echo $a; $a++;}?>
こうすると、$a
は関数が最初にコールされたときにのみ初期化され、
test()
関数がコールされるたびに $a
の値を出力してその値を増加させます。
static変数は、再帰関数を実現する1つの手段としても使用されます。再帰
関数は、自分自身をコールする関数です。再帰関数を書くときには、無限
に再帰を行う可能性があるため、注意する必要があります。適当な方法に
より再帰を確実に終了させる必要があります。次の簡単な関数は、中止す
るタイミングを知るためにstatic変数$count
を用いて、
10 回まで再帰を行います。
例6 再帰関数での静的変数の使用
<?phpfunction test(){ static $count = 0; $count++; echo $count; if ($count < 10) { test(); } $count--;}?>
静的変数には、定数式の結果としての値を代入できますが、 関数呼び出しのような動的な式の結果を代入すると、パースエラーになります。
例7 静的変数の宣言
<?phpfunction foo(){ static $int = 0; // 正しい static $int = 1+2; // 正しい static $int = sqrt(121); // 間違い(関数を使っています) $int++; echo $int;}?>
注意:
静的な宣言は、コンパイル時に解決されます。
グローバル変数と静的変数のリファレンス
PHP は、
リファレンス
変数の修正子として
static および
global
を実装しています。
例えば、関数スコープ内にglobal
命令により実際にインポートされた真のグローバル変数は、
実際にグローバル変数へのリファレンスを作成します。
これにより、以下の例が示すように予測できない動作を引き起こす可能性
があります。
<?phpfunction test_global_ref() { global $obj; $new = new stdclass; $obj = &$new;}function test_global_noref() { global $obj; $new = new stdclass; $obj = $new;}test_global_ref();var_dump($obj);test_global_noref();var_dump($obj);?>
上の例の出力は以下となります。
NULL object(stdClass)#1 (0) { }
類似の動作がstatic
命令にも適用されます。
リファレンスは静的に保存することができません。
<?phpfunction &get_instance_ref() { static $obj; echo 'Static object: '; var_dump($obj); if (!isset($obj)) { $new = new stdclass; // Assign a reference to the static variable $obj = &$new; } if (!isset($obj->property)) { $obj->property = 1; } else { $obj->property++; } return $obj;}function &get_instance_noref() { static $obj; echo 'Static object: '; var_dump($obj); if (!isset($obj)) { $new = new stdclass; // Assign the object to the static variable $obj = $new; } if (!isset($obj->property)) { $obj->property = 1; } else { $obj->property++; } return $obj;}$obj1 = get_instance_ref();$still_obj1 = get_instance_ref();echo "\n";$obj2 = get_instance_noref();$still_obj2 = get_instance_noref();?>
この例を実行すると以下の出力となります。
Static object: NULL Static object: NULL Static object: NULL Static object: object(stdClass)#3 (1) { ["property"]=> int(1) } +
この例は、static変数にリファレンスを代入した時に
&get_instance_ref()
関数を2回目に
コールした際に保持されていないことを示しています。