注:これは、PHPで変数スコープを処理するための参照質問です。このパターンに一致する多くの質問のいずれかを閉じてください。
PHPの「変数スコープ」とは何ですか?ある.phpファイルの変数は別の.phpファイルからアクセス可能ですか?なぜ"undefined variable"エラーが発生するのですか?
変数には、限られた「スコープ」、または「アクセス可能な場所」があります。アプリケーションで$foo = 'bar';
を1回somewhereと書いたからといって、$foo
fromeverywhereその他のアプリケーション内。変数$foo
には有効な特定のスコープがあり、同じスコープ内のコードのみが変数にアクセスできます。
非常に簡単:PHPには関数スコープがあります。これは、PHPに存在する唯一のスコープセパレーターです。関数内の変数は、その関数内でのみ使用可能です。関数の外部の変数は、関数の外部ではどこでも使用できますが、関数の内部では使用できません。これは、PHPに1つの特別なスコープがあることを意味します:globalスコープ。関数の外部で宣言された変数は、このグローバルスコープ内にあります。
<?php
$foo = 'bar';
function myFunc() {
$baz = 42;
}
$foo
はglobalスコープにあり、$baz
はlocalmyFunc
内のスコープ。 myFunc
内のコードのみが$baz
にアクセスできます。コードoutsidemyFunc
のみが$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
sのみです。スコープの目的で、コードのコピーと貼り付けなどのファイルを含めることを考えることができます。
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
は、関数の引数として明示的にこのスコープに入ります。この関数を見るだけで、それが機能する値がどこから由来するかが明確になります。次に、値を明示的にreturnsします。呼び出し元は、関数が動作する変数と戻り値がどこから来るかを知る自信があります。
$baz = 'baz';
$blarg = foo($baz);
$foo = 'bar';
$baz = function () use ($foo) {
echo $foo;
};
$baz();
無名関数には、その周囲のスコープから$foo
が明示的に含まれます。これは、globalスコープと同じではないことに注意してください。
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?!?!!
この関数が副作用を持っているという兆候はありませんが、まだあります。一部の関数はグローバル状態を変更し、必要とするため、これは非常に簡単に混乱します。関数をstatelessにして、入力に対してのみ動作し、定義された出力を返すようにしたいが、何度呼び出してもかまいません。
可能な限りグローバルスコープを使用しないでください。最も確かに、グローバルスコープからローカルスコープに変数を「プル」しないでください。
関数のスコープ内で定義された変数は外部からアクセスできませんが、その関数が完了した後は値を使用できないという意味ではありません。 PHPには、よく知られているstatic
キーワードがあります。これは、オブジェクト指向PHPで静的メソッドとプロパティを定義するために広く使用されていますが、static
関数内で使用して、静的変数を定義することもできます。
静的変数は、プログラムの実行がこのスコープを離れたときに値を失わない場合、関数のスコープで定義された通常の変数とは異なります。静的変数を使用する次の例を考えてみましょう。
function countSheep($num) {
static $counter = 0;
$counter += $num;
echo "$counter sheep jumped over fence";
}
countSheep(1);
countSheep(2);
countSheep(3);
結果:
1 sheep jumped over fence
3 sheep jumped over fence
6 sheep jumped over fence
static
なしで$counter
を定義した場合、エコー値は毎回、関数に渡される$num
パラメーターと同じになります。 static
を使用すると、追加の回避策なしでこの単純なカウンターを作成できます。
静的変数はローカル関数スコープにのみ存在します。定義されている関数の外部からアクセスすることはできません。したがって、その関数の次の呼び出しまで、値を変更せずに保持することができます。
静的変数は、スカラーまたはスカラー式としてのみ定義できます(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";
}
結果:
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概念を模倣する場合があります。
後者では、実際には静的変数の代わりにクロージャーを使用できます。使用するものは常に開発者が決定しますが、静的変数は再帰で作業する場合に間違いなく有用であり、開発者が気付くに値することに注意する必要があります。
既存の質問と PHPマニュアル がこのほとんどを説明するのに素晴らしい仕事をしているので、質問に対する完全な答えを投稿しません。
しかし、見逃された主題の1つは、一般的に使用される$_POST
、$_GET
、$_SESSION
などを含む superglobals です。これらの変数は、常に使用可能な配列です。 、任意のスコープで、global
宣言なし。
たとえば、この関数はPHPスクリプトを実行しているユーザーの名前を出力します。変数は問題なく関数で使用できます。
<?php
function test() {
echo $_ENV["user"];
}
「グローバルは悪い」という一般的なルールは、誤用されていない限り、PHPで「グローバルは悪いが、スーパーグローバルは大丈夫」に修正されています。 (これらの変数はすべて書き込み可能であるため、本当にひどい場合は依存関係の注入を避けるために使用できます。)
これらの変数の存在は保証されていません。管理者はvariables_order
で php.ini
ディレクティブ を使用してそれらの一部またはすべてを無効にできますが、これは一般的な動作ではありません。
現在のスーパーグローバルのリスト:
$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
。コンテンツは、request_order
の- php.ini
ディレクティブ によって決定されます。$_ENV
-現在のスクリプトの環境変数