1. ホーム
  2. php

[解決済み] 参考 変数スコープとは何か、どの変数がどこからアクセス可能か、「未定義変数」エラーとは何か?

2022-04-29 01:21:21

質問

<ブロッククオート

注:これはPHPで変数スコープを扱うための参考問題です。このパターンに当てはまる多くの質問は、この質問と重複しているものとして閉じてください。

PHPにおけるquot;変数スコープ"とは何ですか?ある .php ファイルの変数に別の .php ファイルからアクセスできますか? なぜ時々 "未定義変数" というエラーが発生します。

解決方法を教えてください。

変数スコープとは何ですか?

変数には、限られたquot;scope"(アクセス可能な場所)があります。例えば $foo = 'bar'; 一度 どこかで をアプリケーションで参照できるわけではありません。 $foo から どこでも アプリケーション内部で他の 変数 $foo は有効なスコープが決まっており、同じスコープのコードだけがその変数にアクセスできます。

PHPでは、スコープはどのように定義されるのですか?

非常にシンプルです。PHPは 関数スコープ . PHPに存在するスコープセパレータはこれだけです。関数内の変数は、その関数の内部でのみ使用可能です。関数の外側の変数は、関数の外側のどこでも使用できますが、 どの関数の内側でも使用できるわけではありません。つまり、PHP には特殊なスコープがひとつあります。 グローバル のスコープを使用します。どの関数の外側で宣言された変数も、このグローバルスコープに含まれます。

<?php

$foo = 'bar';

function myFunc() {
    $baz = 42;
}

$foo グローバル のスコープを使用します。 $baz ローカル 内のスコープ myFunc . の中のコードのみです。 myFunc にアクセスすることができます。 $baz . コードのみ myFunc にアクセスすることができます。 $foo . どちらも他方にはアクセスできません。

<?php

$foo = 'bar';

function myFunc() {
    $baz = 42;

    echo $foo;  // doesn't work
    echo $baz;  // works
}

echo $foo;  // works
echo $baz;  // doesn't work

スコープとインクルードファイル

ファイルの境界は 分離しない スコープを使用します。

a.php

<?php

$foo = 'bar';

b.php

<?php

include 'a.php';

echo $foo;  // works!

にも同じルールが適用されます。 include d のコードに適用されるのは、他のコードに適用されるのと同じです。 function は別のスコープを持つ。スコープの目的には、コードをコピー&ペーストするようなファイルを含むと考えるとよいでしょう。

c.php

<?php

function myFunc() {
    include 'a.php';

    echo $foo;  // works
}

myFunc();

echo $foo;  // doesn't work!

上記の例では a.php の中に含まれていた myFunc の中にある変数は a.php はローカル関数のスコープしか持ちません。ただ、それらが 現れる でグローバルスコープにあることを示す。 a.php が必ずしもそうであるとは限りません。実際には、そのコードがどのコンテキストでインクルード/実行されるかに依存します。

関数やクラスの中の関数はどうなりますか?

すべての新しい function の宣言は新しいスコープを導入する、それだけです。

(関数の中の(匿名)関数

function foo() {
    $foo = 'bar';

    $bar = function () {
        // no access to $foo
        $baz = 'baz';
    };

    // no access to $baz
}

クラス

$foo = 'foo';

class Bar {

    public function baz() {
        // no access to $foo
        $baz = 'baz';
    }

}

// no access to $baz

スコープは何に適しているのか?

スコープの問題への対処は煩わしいと思われるかもしれませんが 複雑なアプリケーションを書くには、変数のスコープを限定することが重要です。 もし、あなたが宣言したすべての変数が、アプリケーション内の他のどこからでも利用できるとしたら、何がどのように変化したかを追跡する本当の方法がないまま、変数を踏み倒すことになるでしょう。変数に付けられる名前は限られているので、おそらく " という変数を使いたいでしょう。 $name は、複数の場所で使用されています。もしこのユニークな変数名をアプリ内で一度しか使えないとしたら、変数がユニークであることを確認し、間違ったコードの部分から間違った変数を変更していないことを確認するために、非常に複雑な命名スキームに頼らなければならないでしょう。

観察してください。

function foo() {
    echo $bar;
}

もしスコープがなかったら、上記の関数は何をするのでしょうか?また $bar はどこから来たのか?それはどんな状態なのでしょうか?初期化されているのか?いちいち確認する必要があるのか?これではメンテナンスができません。そこで...

スコープの境界を越える

正しい方法:変数の入出力を行う

function foo($bar) {
    echo $bar;
    return 42;
}

変数 $bar は関数の引数としてこのスコープに明示的に入ってきています。この関数を見ただけで、この関数が扱う値がどこから来たのかがわかります。次に、この関数は明示的に は以下を返します。 という値です。呼び出し側は、この関数がどのような変数を扱うのか、そしてその戻り値はどこから来るのかを確信することができます。

$baz   = 'baz';
$blarg = foo($baz);

変数のスコープを無名関数に拡張する

$foo = 'bar';

$baz = function () use ($foo) {
    echo $foo;
};

$baz();

この匿名関数は、明示的に $foo をその周囲のスコープから削除します。これは グローバル のスコープを使用します。

間違った方法 global

先に述べたように、グローバルスコープはやや特殊で、関数はそこから明示的に変数をインポートすることができます。

$foo = 'bar';

function baz() {
    global $foo;
    echo $foo;
    $foo = 'baz';
}

この関数は、グローバル変数 $foo . このようなことはしないでください <サブ (あなたが本当に本当に本当に何をやっているのか分かっているのであれば別ですが、そうでない場合は: いけません!)

この関数の呼び出し元が見ているのは、これだけです。

baz(); // outputs "bar"
unset($foo);
baz(); // no output, WTF?!
baz(); // outputs "baz", WTF?!?!!

この関数には、何も表示されていません。 サイドエフェクト しかし、それはそうです。これは非常に簡単で、いくつかの関数が を要求し グローバルな状態です。関数は ステートレス 何度呼び出しても、入力に対してのみ動作し、定義された出力を返します。

グローバルスコープの使用はできるだけ避け、グローバルスコープからローカルスコープに変数を「プル&クオット」してはいけません。