18.

PHP 変数スコープ完全ガイド (global / static / use / Arrow Function)

編集
この記事の要点
  • PHP の変数スコープは 関数内 / メソッド内 / グローバルの 3 種が基本。関数の外で定義した変数は関数内で参照できない
  • 関数内からグローバル変数にアクセスするには global $var または $GLOBALS["var"]
  • 関数呼び出しを跨いで値を保持するには static $var
  • Closure は use ($var) で外側変数を取り込む(値渡し / &$var で参照渡し)
  • PHP 7.4+ の Arrow Function (fn() => ...) は外側スコープを自動キャプチャ

変数スコープの基本

PHP の変数は定義した場所によって参照できる範囲が決まる仕組みです。これをスコープと呼びます。

<?php
$globalVar = 'グローバル';

function testScope() {
    // ❌ ここから $globalVar は見えない
    echo $globalVar ?? 'undefined';
    // → undefined (PHP 8+ は警告も出る)

    $localVar = 'ローカル';
    echo $localVar;       // OK
}

testScope();

// ❌ 関数内の $localVar は外から見えない
echo $localVar ?? 'undefined';
// → undefined

global キーワード

関数内からグローバル変数を読み書きしたい場合に global を宣言します:

<?php
$config = ['debug' => true];

function showConfig() {
    global $config;        // ★ グローバルから取り込む
    var_dump($config);
}

showConfig();   // ['debug' => true]

// 同じことは $GLOBALS でも可能
function showConfig2() {
    var_dump($GLOBALS['config']);
}

// ⚠️ アンチパターン: グローバル変数は依存関係が見えなくなる
// 推奨は引数渡し or DI
function showConfigBetter(array $config) {
    var_dump($config);
}
showConfigBetter($config);

static 変数: 関数呼び出しを跨いで保持

<?php
function counter() {
    static $count = 0;   // 初回のみ初期化、以降は前回値を保持
    $count++;
    return $count;
}

echo counter();  // 1
echo counter();  // 2
echo counter();  // 3

// クラスの static プロパティとは別物(こちらは関数ローカル)
class Singleton {
    private static ?self $instance = null;

    public static function get(): self {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
}

関数引数: 値渡し vs 参照渡し

<?php
// 値渡し(デフォルト)
function addOneValue(int $n): void {
    $n++;
    // 関数内の変更は呼び出し元に影響しない
}

$x = 10;
addOneValue($x);
echo $x;  // 10

// 参照渡し(& を引数前に)
function addOneRef(int &$n): void {
    $n++;
}

$y = 10;
addOneRef($y);
echo $y;  // 11

// 配列も同じ。配列は値渡しでもコピーされるので注意
function pushOne(array &$arr): void {
    $arr[] = 'new';
}

$items = ['a'];
pushOne($items);
print_r($items);  // ['a', 'new']

Closure と use 句

無名関数(Closure)は外側スコープを自動では取り込まないのが PHP の特徴。use で明示的に渡します:

<?php
$prefix = '[INFO] ';

// ❌ NG: $prefix は Closure 内では未定義
$logger = function ($msg) {
    echo $prefix . $msg;
    // → Undefined variable: prefix
};

// ✅ use で取り込む(値渡し)
$logger = function ($msg) use ($prefix) {
    echo $prefix . $msg;
};
$logger('ok');   // [INFO] ok

// 参照渡し: Closure 内で外側変数を変更できる
$count = 0;
$inc = function () use (&$count) {
    $count++;
};
$inc(); $inc(); $inc();
echo $count;  // 3

// 値渡しと参照渡しのコンビ
$adder = function ($n) use ($prefix, &$count) {
    $count += $n;
    return $prefix . $count;
};

PHP 7.4+ Arrow Function は自動キャプチャ

<?php
$prefix = '[INFO] ';

// ✅ Arrow Function は use 不要、自動キャプチャ
$logger = fn($msg) => $prefix . $msg;
echo $logger('ok');   // [INFO] ok

// 1 式しか書けない(return が暗黙)
// 複数行 / 副作用が必要なら通常の Closure を使う

// 配列操作で重宝
$users = [['age' => 30], ['age' => 20], ['age' => 40]];
$ages = array_map(fn($u) => $u['age'], $users);
$adults = array_filter($users, fn($u) => $u['age'] >= 20);

// 注意: Arrow Function は値渡し(参照渡し不可)
$count = 0;
$inc = fn() => $count++;  // 外側 $count は変わらない
$inc();
echo $count;  // 0

クラスのスコープ修飾子

修飾子意味アクセス
public公開どこからでも
protected保護同クラス + 継承先
private非公開同クラスのみ
self::クラス自身定義したクラス参照
static::遅延静的束縛呼び出し元クラスを参照
parent::親クラス継承元参照
<?php
class Base {
    public static function create(): self {
        return new self();    // 常に Base
    }
    public static function createStatic(): static {
        return new static();  // 呼び出し元のクラス
    }
}

class Child extends Base {}

var_dump(Base::create());          // Base
var_dump(Child::create());         // Base ★ (self は静的束縛)
var_dump(Child::createStatic());   // Child ★ (static は遅延静的束縛)

ベストプラクティス

  • グローバル変数は使わない: テスト困難・依存関係不明・並列実行で衝突
  • 関数 / メソッドは引数で必要な値を受ける
  • クラスはDI コンテナ (Container) 経由で依存を注入
  • Closure はuse 句を最小限に(多すぎたら別関数化)
  • static 変数はメモ化など限定用途のみ。状態を持つならクラス化

FAQ

Q: global $var$GLOBALS["var"] どちらが推奨?
A: どちらも非推奨だが、止むを得ず使うなら $GLOBALS。理由は global 宣言を後で見落としやすいから。最善はどちらも使わず引数渡し

Q: Arrow Function で複数行書きたい
A: 仕様上 1 式のみ。複数行が必要なら通常の function () use (...) {} を使ってください。

Q: self::static:: の使い分け
A: 継承先で挙動を上書きしたいなら static::(遅延静的束縛)。固定したいなら self::。ファクトリメソッドは static:: が一般的です。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 基本事項
  2. HTMLへの埋め込み
  3. 変数
  4. 可変変数
  5. 定数
  6. データ型
  7. キャスト
  8. エスケープ文字
  9. 配列
  10. 演算子
  11. 代入の際の注意点
  12. 条件分岐
  13. 繰り返し処理
  14. クラスとインスタンス
  15. コンストラクタ
  16. 関数
  17. スーパーグローバル変数
  18. スコープ
  19. staticについて
  20. yieldについて
  21. ファイルのアップロード方法
  22. DB接続方法
  23. SQL実行方法
  24. カプセル化の具体例
  25. 継承の構文
  26. オーバーライド
  27. ポリモーフィズム(多様性)の具体例
  28. 抽象クラス・メソッドの構文と具体例
  29. GET通信
  30. try catchで全てのエラーを拾う方法

最近更新/作成されたページ