参考にさせていただきます。変数スコープとは何か、どの変数がどこからアクセスできるのか、"未定義変数 "エラーとは何か

php scope


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

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





Answer 1 deceze


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

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

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

非常にシンプル:PHPには関数スコープがあります。 これは、PHPに存在する唯一のスコープセパレータです。 関数内の変数は、その関数内でのみ使用できます。 関数外の変数は、関数外のどこでも使用できますが、関数内では使用できません。 つまり、PHPには1つの特別なスコープ、つまりグローバルスコープがあります。 関数の外部で宣言された変数は、このグローバルスコープ内にあります。

Example:

<?php

$foo = 'bar';

function myFunc() {
    $baz = 42;
}

$fooグローバルスコープにあり、 $bazmyFunc 内のローカルスコープにあります 。 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内に含まれて myFunca.php 内の変数はローカル関数スコープのみを持っています。 それら a.php のグローバルスコープにあるように見えるからといって、必ずしもそうであるとは限らないため、実際には、コードが含まれている/実行されているコンテキストによって異なります。

関数やクラスの中の関数は?

すべての新しい function 宣言は新しいスコープを導入し、それはとても簡単です。

関数内関数

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

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

    // no access to $baz
}

classes

$foo = 'foo';

class Bar {

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

}

// no access to $baz

スコープは何のためにあるのか?

スコーピングの問題に対処するのは面倒なように思えるかもしれませんが、 複雑なアプリケーションを作成するには限られた変数スコープが不可欠です。 宣言したすべての変数がアプリケーション内の他のどこからでも利用できる場合、何が何を変更するかを追跡する実際の方法がなく、変数をすべてステップオーバーすることになります。 変数に付けることができる $name は非常に多くあります。おそらく、変数 " $ name "を複数の場所で使用したいと思うでしょう。 アプリでこの一意の変数名を1回しか使用できない場合、変数が一意であり、間違った変数を間違ったコードから変更していないことを確認するために、非常に複雑な命名規則に頼る必要があります。

Observe:

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

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

どのような方法であれ、グローバルスコープを使用することは可能な限り避けるべきであり、最も確かなことは、グローバルスコープからローカルスコープに変数を「引っ張り出す」ことではないということです。




Answer 2 Alex Myznikov


関数のスコープ内で定義された変数に外部からアクセスすることはできませんが、関数が完了した後でその値を使用できないことを意味しません。 PHPには、静的メソッドとプロパティを定義するためにオブジェクト指向PHPで広く使用されている有名 static キーワードがありますが、 static を定義するために関数内でもstaticを使用できることに注意してください。

「静的変数」とは何ですか?

静的変数は、関数のスコープに定義されている通常の変数とは異なり、プログラムの実行がこのスコープから外れても値が失われないという点が異なります。静的変数を使用する場合の例を考えてみましょう。

function countSheep($num) {
 static $counter = 0;
 $counter += $num;
 echo "$counter sheep jumped over fence";
}

countSheep(1);
countSheep(2);
countSheep(3);

Result:

1 sheep jumped over fence
3 sheep jumped over fence
6 sheep jumped over fence

static なしで $counter を定義した場合、エコーされる値は $num 、関数に渡される$ numパラメーターと同じになります。 static を使用すると、追加の回避策なしでこの単純なカウンターを構築できます。

静的変数の使用例

  1. 関数の呼び出しの間に値を保存します。
  2. パラメータとして渡す方法がない(または目的がない)場合に、再帰的な呼び出しの間に値を保存します。
  3. 通常は一度取得した方が良い値をキャッシュします。例えば、サーバ上の不変ファイルを読み込んだ結果などです。

Tricks

静的変数はローカル関数スコープ内にのみ存在します。定義された関数の外部からはアクセスできません。そのため、次にその関数を呼び出すまで値を変更しないようにしておくとよいでしょう。

静的変数はスカラかスカラ式でしか定義できません (PHP 5.6 以降)。これに他の値を代入すると、少なくともこの記事が書かれた時点では必然的に失敗することになります。それにもかかわらず、コードの次の行でそれを行うことができます。

function countSheep($num) {
  static $counter = 0;
  $counter += sqrt($num);//imagine we need to take root of our sheep each time
  echo "$counter sheep jumped over fence";
}

Result:

2 sheep jumped over fence
5 sheep jumped over fence
9 sheep jumped over fence

静的関数は、同じクラスのオブジェクトのメソッド間で共有されています。以下の例を見ていただくとわかりやすいと思います。

class SomeClass {
  public function foo() {
    static $x = 0;
    echo ++$x;
  }
}

$object1 = new SomeClass;
$object2 = new SomeClass;

$object1->foo(); // 1
$object2->foo(); // 2 oops, $object2 uses the same static $x as $object1
$object1->foo(); // 3 now $object1 increments $x
$object2->foo(); // 4 and now his twin brother

これは、同じクラスのオブジェクトに対してのみ動作します。オブジェクトが異なるクラスのものであれば (互いに拡張している場合でも)、静的変数の動作は期待通りになります。

静的変数は、関数の呼び出し間で値を保持する唯一の方法ですか?

関数呼び出しの間に値を保持するもうひとつの方法は、クロージャを使用することです。クローサは PHP 5.3 で導入されました。つまり、関数スコープ内の変数へのアクセスを匿名の関数に限定し、その関数が唯一のアクセス手段となるということです。クロージャ内にある変数は、構造化プログラミングにおける 'クラス定数' (値でクロージャに渡された場合)や 'プライベートプロパティ' (参照で渡された場合)のような OOP の概念を (多かれ少なかれ)真似しているかもしれません。

後者の方が実際には静的変数の代わりにクロージャを使うことができます。何を使うかは常に開発者の判断に委ねられていますが、静的変数は再帰処理を行う際には間違いなく有用であり、開発者の注目を集めるに値するものであることを述べておきます。




Answer 3 miken32


既存の質問とPHPのマニュアルはこれのほとんどを説明するのに優れているので、質問に対する完全な回答は掲載しません。

しかし、見落とされた1つの主題は、一般的に使用される $_POST$_GET$_SESSION などを含むスーパーグローバルの主題でした。これらの変数は、 global 宣言なしで、どのスコープでも常に使用可能な配列です。

例えば、この関数はPHPスクリプトを実行しているユーザーの名前を出力します。この変数は問題なく関数で利用できるようになっています。

<?php
function test() {
    echo $_ENV["user"];
}

グローバルは悪い」という一般的なルールは、悪用していない限り、PHPでは一般的に「グローバルは悪いが、スーパーグローバルは大丈夫」というように修正されています。(これらの変数はすべて書き込み可能なので、下手をすれば依存性注入を避けるために使うことができます)。

これらの変数が存在することは保証されていません。 管理者は php.ini variables_order ディレクティブを使用してそれらの一部またはすべてを無効にできますが、これは一般的な動作ではありません。


現在のスーパーグロバルのリスト。

  • $GLOBALS 現在のスクリプトのすべてのグローバル変数
  • $_SERVER サーバーと実行環境に関する情報
  • $_GET リクエストに使用されるHTTPメソッドに関係なく、URLのクエリ文字列で渡される値
  • $_POST - application/x-www-form-urlencoded または multipart/form-data MIMEタイプでHTTP POSTリクエストに渡される値
  • $_FILES - multipart/form-data MIMEタイプのHTTP POSTリクエストで渡されたファイル
  • $_COOKIE 現在のリクエストで渡されたCookie
  • $_SESSION -PHPによって内部的に保存されたセッション変数
  • $_REQUEST 通常は $_GET$_POST 組み合わせですが、場合によっては $_COOKIES です。 内容は php.ini request_order ディレクティブによって決定されます。
  • $_ENV 現在のスクリプトの環境変数