前回
- 副作用をもつ関数
- 関数表記方法・変数との表記方法の違い
スコープ
- グローバル(つまり関数の外側)スコープ・関数レベルのスコープ
- マクロで言う、Public/Private
- 関数内から、外にある変数にアクセスしたいときはglobalを使う
- ここからの出題は、スコープを使って出力がどうなるかを問う問題が多い
スコープに関する問題
さて、下記は1を出力するか否か?
function test() {
$x = 1;
}
$x = test();
echo $x;
解答
正解は、「何も出力しない」
なぜなら、 関数内で、$x = 1を出していてもそれを関数の外に出す処理をしていないため
外側の$xには何も値が入らないからである。
正確には、下のように書けば、1が出力される。
function test() {
$x = 1;
return $x;
}
$x = test();
echo $x;
つまり、「return」で、$xを外に出せるようになるということ。
スコープに関する問題2
さて、下記は1を出力するか否か?
function test() {
global $x;
echo $x;
}
$x = 1;
test();
解答
正解は「Yes」
functionは本処理の前でも後ろでもどこにおいてもOK。(今回は前においてる)
ただし、処理の順番は本処理からで、$x=1がはいり、test()をコールする、という順番になる。
関数の外で$xに1が代入され、その後にtest()をコール。
globalがついているので、関数内の$xには1が入る。
それを出力するので1となる。
※
こんなふうに出題されるときは、スコープ変換、returnのあるなしによって値が入るかどうかを見る問題が多いです。
# スタティック(静的)変数
- 関数内の変数は関数の呼び出しが完了したら消える
- それを防ぐのがstaticキーワード。関数呼び出し後も変数の値を保持する
- ただし、staticキーワードがついた関数の代入は最初の呼び出しのときだけ
さて、以下の出力は何になるか?
答えを見る前に考えよう (問題以下にちょっと空白入れます)
function test() {
static $x = 0;
$x++;
echo $x,"\n";
}
test();
test();
test();
呼び出されるのは$xだが、1回目は0から1に変化。
staticの場合、その(親)関数の最初の呼び出しのときだけ変数の代入が行われる
そのため2回めに呼び出されたときは、staticで$xは0に初期化されない。
そのため、結果は、下記の通り、
1
2
3
というような文字が出力される。(\nは「改行」。なければ123に)
これが大原則。
問題としては、複数のスタティック変数を用意し、処理結果が何になるかという応用問題が考えられる。
というわけでちょっと作ってみた。
さて、以下の出力は何になるか?
答えを見る前に考えよう。
static $y = 10;
function test() {
static $x = 0;
global $y;
$x++;
$y++;
echo $x."<br>";
echo $y. "<br>";
}
test();
test();
test();
echo $x."<br>";
echo $y;
自分で適当にやっててこんな凶悪な、もとい、応用問題作れると思わなかった。
ですがこれは解きがいがあっておもしろい。
まず大原則として、プログラムは上から下へ流れるという性質がある。
したがって、1行目のstatic変数$y=10;は
グローバル・スタティックな変数としてまず認識される。
つぎの行はfunctionなので、とばしていくと、test()が3回ある。
test()を3回繰り返すということ。
では次にfunction内で、test()の中身を。
static変数$xが定義され、$xの値は0。
次に、globalでグローバル変数$yへアクセス可能に。
ここで$yには10が入る。
つぎに$xと$yにそれぞれ1ずつ足す。 それぞれ1と、11。
それらがエコー。
それを2回繰り返す。ただし、staticは最初の1回だけなので、ここは無視される。
そしてそれぞれ2回繰り返されるので2と12,3と13がでる。
つぎにグローバルで、$xをエコーするが、
$xは関数の中だけの変数なので、$xは何も入っていないため空白が出力。
$yはグローバル変数でかつ、関数内にアクセスされ、+3されたので、13が出力
というわけで答えは、
1
11
2
12
3
13
(空白)
13
となる。
記事作成の裏側
上記の問題を実際にコードで書いて実行してみたら、エラーになってしまって、修正をしていたが、
$ははいってる、;もある、なぜだ。。。とドツボにハマった。
結局はコードの前のスペースが半角ではなく全角スペースになっていたから。
Qiitaだとタブがきかないので、スペースで入れるが、時々半角にするの忘れて全角で入れるミスがある。
気をつけたい。
こういうこともあるのだなということで共有。
次回は、値渡しと参照渡し、パラメータのデフォルト値、可変関数、匿名関数、言語構造になる。