LoginSignup
1
1

More than 3 years have passed since last update.

【PHP】変数のスコープのお話

Posted at

関数の内部から、グローバルスコープの変数へアクセスすることはできない。

まずは、このコードをご覧ください。

$a = 0;
function hoge () {
    $a++; // Undefined variable: a
}

hoge();
echo $a; // 0

期待した動作としては、関数の中で変数$aの値をインクリメントして、1増えた値を出力してくれるものでした。
どうして期待とは異なった動作をしたのでしょうか。

それは、関数の中と外で変数のスコープが異なることに原因があります。

通常、関数の外側で定義された変数はグローバルスコープとなり、関数の内部で定義された変数は、ローカルスコープとなります。
(ちなみに、PHPにブロックスコープはありません)

// グローバルスコープ
$a = 0; 
function hoge () {
    // ローカルスコープ
    $a++;
}
//グローバルスコープ
hoge();
echo $a;

しかし、特に他の言語を学んだことのある方なら、グローバルスコープとローカルスコープの関係について、このようなイメージをお持ちではないでしょうか?

image.png

グローバルスコープからローカルスコープへのアクセスは禁止されているけれど、ローカルスコープはグローバルスコープの一部なので、グローバル変数も使用可能、といった感じです。

しかし、実際にはこんなだいたいこんなイメージだと思ってください。

image.png

そもそも、お互いに離れているので、通常はアクセスすることができないといった感じです。

通常は、引数として渡してやるのが一般的です。


$a = 0; 
function hoge ($a) {
    $a++;
}

hoge();
echo $a; // 0

エラーはでなくなりましたが、以前出力される値は0のままです。
これは、関数に変数を渡すときは、変数そのものを受け渡しているのではなく、変数の中身をコピーして渡している(値渡し)からです。

変数そのものを渡す(参照渡し)ときには、&をつけてあげます。


$a = 0; 
function hoge (&$a) {
    $a++; // グローバルスコープの変数と同じもの
}

hoge();
echo $a; // 1

また、あまり使われませんが変数の前にglobalと宣言することで、引数として渡さなくても関数の内部からグローバル変数へアクセスすることが可能です。


$a = 0; 
function hoge () {
    global $a; // 明示的にグローバルな変数にアクセスする
    $a++; 
}

hoge();
echo $a; // 1

話は少々横道にそれますが、PHPにはスーパーグローバル変数というものがあります。
スーパーとついているだけあって、この変数はグローバルスコープだろうがローカルスコープだろうが、どんな場所でもアクセスすることが可能です。


$a = 0; 
function hoge () {
    // これはグローバルスコープに現在定義されているすべての変数への参照を含む連想配列
    $GLOBALS['a']++;

    // これらもグローバススコープの一種
    $_GET['address'];
    $_POST['address'];
}

hoge();
echo $a; // 1

無名関数の内部から外の変数を使う

無名関数の内部で、親のスコープから変数を引き継ぐ場合には、useを使います。

<?php

$array = ['APPLE', 'LEMON', 'BANANA'];
$case_insensitive = true;

$red_fruits = array_filter($array, function($value) use($case_insensitive) {
    if ($case_insensitive) {
        $value = mb_strtolower($value);
    }
    return $value === 'apple';
});

print_r($red_fruits);
// Array ( [0] => APPLE )

これは、先程の例のように、グローバルスコープの変数にアクセスする場合とは、違うことに注意しましょう。

<?php
$array = ['APPLE', 'LEMON', 'BANANA'];
$case_insensitive = true;

function func($array) {
    $case_insensitive = false;

    $red_fruits = array_filter($array, function($value) use($case_insensitive) {
        if ($case_insensitive) {
            $value = mb_strtolower($value);
        }
        return $value === 'apple'
    });

    print_r($red_fruits);
}
func($array);
// Array ( )

無名関数を関数の中に閉じ込めてあげると、先程とはことなり、そのスコープ内の変数を取り込んでいることがわかります。
グローバルスコープの変数は使われておりません。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1