174

注: これは、PHP で変数のスコープを処理するための参照用の質問です。このパターンに当てはまる多くの質問は、このパターンの重複としてクローズしてください。

PHPの「変数スコープ」とは何ですか? ある .php ファイルの変数は別のファイルでアクセスできますか? 「未定義変数」エラーが時々発生するのはなぜですか?

4

3 に答える 3

196

「可変範囲」とは?

変数には、「スコープ」または「変数にアクセスできる場所」が制限されています。アプリケーションのどこか$foo = 'bar';に一度書いたからといって、アプリケーション内の他の場所から参照できるわけではありません。変数には有効な特定のスコープがあり、同じスコープ内のコードのみが変数にアクセスできます。$foo$foo

スコープはPHPでどのように定義されていますか?

非常に単純です: PHP にはfunction scopeがあります。これは、PHP に存在する唯一のスコープ区切り文字です。関数内の変数は、その関数内でのみ使用できます。関数外の変数は、関数外のどこでも使用できますが、関数内では使用できません。これは、PHP に 1 つの特別なスコープ、つまりグローバルスコープがあることを意味します。関数の外で宣言された変数はすべて、このグローバル スコープ内にあります。

例:

<?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!

他のコードに適用されるのと同じルールがincluded コードに適用され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" を複数の場所で使用したい場合があります。この一意の変数名をアプリで 1 回しか使用できない場合は、変数が一意であること、および間違ったコードから間違った変数を変更していないことを確認するために、非常に複雑な命名スキームに頼る必要があります。

観察:

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?!?!!

この関数に副作用があるという兆候はありませんが、実際にはあります。一部の関数は変更を続け、何らかのグローバル状態を必要とするため、これは非常に簡単に絡み合った混乱になります。関数をステートレスにして、入力に対してのみ動作し、定義された出力を返す必要がありますが、何度呼び出してもかまいません。

可能な限り、グローバル スコープの使用を避ける必要があります。最も確実なのは、変数をグローバルスコープからローカルスコープに「プル」するべきではありません。

于 2013-06-06T10:20:35.760 に答える