注:これは、PHPで変数スコープを処理するための参照質問です。このパターンの複製として、このパターンに当てはまる多くの質問のいずれかを閉じてください。
PHPの「変数スコープ」とは何ですか?ある.phpファイルの変数は別の.phpファイルからアクセスできますか?なぜ「未定義の変数」エラーが発生するのですか?
注:これは、PHPで変数スコープを処理するための参照質問です。このパターンの複製として、このパターンに当てはまる多くの質問のいずれかを閉じてください。
PHPの「変数スコープ」とは何ですか?ある.phpファイルの変数は別の.phpファイルからアクセスできますか?なぜ「未定義の変数」エラーが発生するのですか?
回答:
変数には、「スコープ」または「アクセス可能な場所」に制限があります。アプリケーションのどこかで$foo = 'bar';
一度書いたからといって、アプリケーション内のどこ$foo
からでも参照できるというわけではありません。変数$foo
には有効範囲がある特定のスコープがあり、同じスコープ内のコードのみが変数にアクセスできます。
非常にシンプル:PHPには関数スコープがあります。これは、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!
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
意味のある名前は非常に多く、変数 " "を複数の場所で使用したい場合があります。アプリでこの一意の変数名を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?!?!!
この関数に副作用があることを示すものはありませんが、副作用はあります。一部の関数は変更を続け、いくつかのグローバルな状態を必要とするため、これは非常に簡単に混乱します。関数をステートレスにして、入力にのみ作用し、定義された出力を返すようにしますが、何度も呼び出します。
グローバルスコープはできるだけ使用しないでください。ほとんどの場合、変数をグローバルスコープからローカルスコープに「プル」することはできません。
global
。それは常に間違っています。関数パラメータを渡すことは正しいです。static
マニュアルでよく説明されており、スコープとはあまり関係がありません。簡単に言えば、「スコープ付きグローバル変数」と考えることができます。ここでkunststube.net/staticの使用法を少し拡張しています。
include_once
し、多分require_once
またどこかに追加する必要がありますが、ただ言って。OPも投票を再開することに投票しました。彼らのポストは特別な場合でしょうか、そしてそれについて何をすべきですか?
関数のスコープ内で定義された変数に外部からアクセスすることはできませんが、その関数が完了した後でその値を使用できないことを意味するわけではありません。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
$counter
なしで定義した場合static
、毎回エコーされる値は$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のマニュアルは、このほとんどの説明に役立つため、質問に対する完全な回答は掲載しません。
しかし逃した一人の被験者は、であったスーパーグローバルなど、一般に使用される$_POST
、$_GET
、$_SESSION
、等が挙げられる。これらの変数はせずに、任意の範囲で、常に利用可能である配列で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
-現在のスクリプトの環境変数