オープンソースのWeb開発向けスクリプト言語「PHP」の文法を一から学ぶための入門連載。今回は、PHPの変数のスコープについて解説します。
オープンソースのWeb開発向けスクリプト言語「PHP」の文法を一から学ぶための入門連載「Web業界で働くためのPHP入門」。
今回のテーマは変数の「スコープ」です。今まで何げなく使っていたPHPの変数ですが、実は「生存できる範囲」があります。この変数が生存できる範囲のことを変数の「スコープ」といいます。
少し例を見てみましょう。リスト1のuseUndefinedVariable.phpを作成し、実行してください。このuseUndefinedVariable.phpは、前回作成したuseUserDefinedFunction.phpを少し改造したものです。
<?php function multiplyArray(array $array) { $num = 1; foreach($array as $value) { $num *= $value; } } $list = [5, 4, 8, 6, 2, 9]; multiplyArray($list); print("配列の計算結果: ".$num);
実行結果は下記のようにエラーになります。
Notice: Undefined variable: num in C:\xampp\htdocs\phplesson\chap10\useUndefinedVariable.php on line 12 配列の計算結果:
エラー内容では、12行目の変数numが未定義、となっています。リスト1を単に眺めているだけだと、4行目で$numが宣言されているので「未定義」というエラーは不思議に思うかもしれません。これは、変数の「スコープ」が原因です。それを理解するために、まず、リスト1の処理の順番を追ってみましょう。図1を見てください。
リスト1は、コードは2行目から始まっていますが、2〜8行目は関数を定義している部分です。そのため、このプログラムが実行される際、実際は10行目から順に実行されます。10行目が実行され、11行目が実行されるときに関数の内部が実行されます。その部分はソースコードでは4〜7行目です。この関数内の処理が終了して初めて11行目の処理が終了します。その後、12行目が処理されます。
このように見ていくと、関数内の変数$numの扱いが少し違って見えてくると思います。
$numは関数内で宣言された変数です。このように関数内で宣言された変数のことを「ローカル変数」といいます。そして、PHPでは、ローカル変数は、その関数内でしか生存できないというルールがあります。つまり、ローカル変数のスコープは関数内のみ、ということであり、これを「ローカルスコープ」といいます。
一方、関数外で宣言された変数、リスト1では$listが該当しますが、これを「グローバル変数」といい、関数外で実行中は生存できるスコープ(グローバルスコープ)を持っています。
そして、PHPではローカルスコープとグローバルスコープは相互に行き来ができないようになっています。
図2からも分かるように、ローカル変数である$numをグローバルスコープで利用しようとしたのがリスト1のエラーの原因です。関数内での計算結果を関数の呼び出し元で利用する場合は、前回解説したように、戻り値を利用するようにしましょう。
先述のように、ローカル変数はローカルスコープのみ、グローバル変数はグローバルスコープのみで参照できるようになっています。しかし、ローカルスコープでもグローバルスコープでも、その両方で参照できる特別な変数があり、それを「スーパーグローバル」といいます。第8回のPHPの「定義済みの変数」で紹介した、$_GETや$_POSTは代表的なスーパーグローバルです。
では、外部ファイルをrequire/includeした場合はどのようになるのでしょうか。以下の例で確認してみましょう。まず、include先ファイルを作成します。
<?php $num++; print("<br>今のnumの値: ".$num);
次に、このファイルを利用するファイルを作成しましょう。
<?php $num = 1; print("include1回目"); include("increment.php"); print("<br>include2回目"); include("increment.php"); print("<br>include3回目"); include("increment.php");
useIncrement.phpの方を実行してください。実行結果は下記の通りです。
include1回目 今のnumの値: 2 include2回目 今のnumの値: 3 include3回目 今のnumの値: 4
まず、リスト2を見てください。未宣言の変数$numをいきなりインクリメントしています。実際、increment.phpを直接実行した場合は「Undefined variable: num」のエラーとなります。ところが、リスト3でこのファイルをincludeした場合はエラーにならず実行できます。前回のコラムにも書きましたが、requireもincludeもその位置に外部ファイルを読み込み、実行する処理です。前回では関数定義のみが記述されたファイルでしたので、イメージしにくかったかもしれませんが、リスト3のように実行可能なファイルを読み込んでも構いません。その場合の処理は図3のようになります。
つまり、外部ファイルに書かれていても、実際に実行される際は以下のようなソースコードと同等となります。
<?php $num = 1; print("include1回目"); $num++; print("<br>今のnumの値: ".$num); print("<br>include2回目"); $num++; print("<br>今のnumの値: ".$num); print("<br>include3回目"); $num++; print("<br>今のnumの値: ".$num);
PHPでは、require/includeされたファイルは、実行時にソースコードが埋め込まれ、結合されるイメージを持ってください。こうすると、リスト2では未定義の変数$numが利用できることを分かってもらえると思います。
といっても、リスト2とリスト3のようにrequire/include先に実行処理を記述し、しかも変数を共用するのはプログラムの可読性が非常に下がり、バグの温床となりがちです。やはり、別ファイルに記述するのはあくまで関数のみとし、実行処理は1つのファイルにまとめるように心掛けましょう。
Copyright © ITmedia, Inc. All Rights Reserved.