参照:変数スコープとは何ですか?どこからアクセスできる変数と「未定義変数」エラーとは何ですか?

168
deceze 2013-06-07 00:20.

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

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

3 answers

188
deceze 2013-06-07 00:20.

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

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

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

非常に単純です: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?!?!!

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

可能な限り、グローバルスコープの使用は避けてください。確かに、変数をグローバルスコープからローカルスコープに「プル」するべきではありません。

9
Alex Myznikov 2017-02-17 11:06.

関数のスコープ内で定義された変数に外部からアクセスすることはできませんが、その関数の完了後にそれらの値を使用できないことを意味するわけではありません。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すると、追加の回避策なしでこの単純なカウンターを構築できます。

静的変数のユースケース

  1. 関数の結果の呼び出しの間に値を格納します。
  2. 値をパラメーターとして渡す方法がない(または目的がない)ときに、再帰呼び出しの間に値を格納すること。
  3. 通常は1回取得する方がよい値をキャッシュします。たとえば、サーバー上の不変ファイルを読み取った結果。

秘訣

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

静的変数は、スカラーまたはスカラー式としてのみ定義できます(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

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

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

関数呼び出し間で値を保持する別の方法は、クロージャを使用することです。クロージャーはPHP5.3で導入されました。つまり、関数スコープ内の変数のセットへのアクセスを、それらにアクセスする唯一の方法となる別の無名関数に制限することができます。クロージャ変数に含まれていると、構造化プログラミングの「クラス定数」(値によってクロージャに渡された場合)や「プライベートプロパティ」(参照によって渡された場合)などのOOP概念を(多かれ少なかれうまく)模倣できます。

後者では、実際には静的変数の代わりにクロージャを使用できます。何を使用するかは常に開発者が決定しますが、静的変数は再帰を処理するときに間違いなく役立ち、開発者が気付くに値することに注意してください。

2
miken32 2019-05-14 04:18.

既存のものと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-dataMIMEタイプを使用してHTTPPOSTリクエストで渡される値
  • $_FILESmultipart/form-data-MIMEタイプのHTTPPOSTリクエストで渡されたファイル
  • $_COOKIE -現在のリクエストで渡されたCookie
  • $_SESSION -PHPによって内部的に保存されたセッション変数
  • $_REQUEST-の典型的組み合わせ$_GET$_POST、時には$_COOKIES。内容は、のrequest_orderディレクティブによって決定されphp.iniます。
  • $_ENV -現在のスクリプトの環境変数

Related questions

MORE COOL STUFF

Reba McEntire は、彼女が息子の Shelby Blackstock と共有する「楽しい」クリスマスの伝統を明らかにしました:「私たちはたくさん笑います」

Reba McEntire は、彼女が息子の Shelby Blackstock と共有する「楽しい」クリスマスの伝統を明らかにしました:「私たちはたくさん笑います」

Reba McEntire が息子の Shelby Blackstock と共有しているクリスマスの伝統について学びましょう。

メーガン・マークルは、自然な髪のスタイリングをめぐってマライア・キャリーと結ばれました

メーガン・マークルは、自然な髪のスタイリングをめぐってマライア・キャリーと結ばれました

メーガン・マークルとマライア・キャリーが自然な髪の上でどのように結合したかについて、メーガンの「アーキタイプ」ポッドキャストのエピソードで学びましょう.

ハリー王子は家族との関係を修復できるという「希望を持っている」:「彼は父親と兄弟を愛している」

ハリー王子は家族との関係を修復できるという「希望を持っている」:「彼は父親と兄弟を愛している」

ハリー王子が家族、特にチャールズ王とウィリアム王子との関係について望んでいると主張したある情報源を発見してください。

ワイノナ・ジャッドは、パニックに陥った休暇の瞬間に、彼女がジャッド家の家長であることを認識しました

ワイノナ・ジャッドは、パニックに陥った休暇の瞬間に、彼女がジャッド家の家長であることを認識しました

ワイノナ・ジャッドが、母親のナオミ・ジャッドが亡くなってから初めての感謝祭のお祝いを主催しているときに、彼女が今では家長であることをどのように認識したかを学びましょう.

セントヘレナのジェイコブのはしごを登るのは、気弱な人向けではありません

セントヘレナのジェイコブのはしごを登るのは、気弱な人向けではありません

セント ヘレナ島のジェイコブズ ラダーは 699 段の真っ直ぐ上る階段で、頂上に到達すると証明書が発行されるほどの難易度です。

The Secrets of Airline Travel Quiz

The Secrets of Airline Travel Quiz

Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

バイオニック読書はあなたをより速く読むことができますか?

バイオニック読書はあなたをより速く読むことができますか?

BionicReadingアプリの人気が爆発的に高まっています。しかし、それは本当にあなたを速読術にすることができますか?

オーケーグッド770HPランボルギーニセンテナリオは十分に正気ではない

オーケーグッド770HPランボルギーニセンテナリオは十分に正気ではない

ランボルギーニの創設者であるフェルッチオランボルギーニが100歳になるのは毎日ではありません(そうです、彼は死んでいて、まだ死んでいると思います。

彼らが買った1台の車からAppleの車の計画について私たちが推測できること

彼らが買った1台の車からAppleの車の計画について私たちが推測できること

Appleが自動車分野に参入するという噂はかなり前から渦巻いており、AppleウォッチャーがSixtyEight Researchという会社がAppleの自動車研究開発のシェル会社である可能性が高いと判断したとき、その渦巻きは本当に渦巻いた。また、会社が購入した車は1台だけであることが知られており、その車はAppleが何を考えているかについての手がかりでいっぱいになる可能性があることも伝えています。

天文学者は太陽系の9番目の惑星の新しい証拠を見つけます

天文学者は太陽系の9番目の惑星の新しい証拠を見つけます

太陽系の外側にある架空の大きな物体である惑星Xの探索は、何十年にもわたって人間を魅了してきました。その検索の最新の章は、地球の10倍の大きさで、公転周期が15であるほど遠くにある惑星を指しています。

キャムニュートン、ゴッドダム

キャムニュートン、ゴッドダム

カムニュートンは昨日、簡単な265ヤードと3回のタッチダウンでファルコンズを引き裂き、別の素晴らしいゲームをしました。その日のハイライトは、上のタッチダウンスローでした。これは、視聴するたびにばかげているだけです。

米国のフィギュア スケートは、チーム イベントでの最終決定の欠如に「苛立ち」、公正な裁定を求める

米国のフィギュア スケートは、チーム イベントでの最終決定の欠如に「苛立ち」、公正な裁定を求める

ロシアのフィギュアスケーター、カミラ・バリエバが関与したドーピング事件が整理されているため、チームは2022年北京冬季オリンピックで獲得したメダルを待っています。

Amazonの買い物客は、わずか10ドルのシルクの枕カバーのおかげで、「甘やかされた赤ちゃんのように」眠れると言っています

Amazonの買い物客は、わずか10ドルのシルクの枕カバーのおかげで、「甘やかされた赤ちゃんのように」眠れると言っています

何千人ものAmazonの買い物客がMulberry Silk Pillowcaseを推奨しており、現在販売中. シルクの枕カバーにはいくつかの色があり、髪を柔らかく肌を透明に保ちます。Amazonで最大46%オフになっている間にシルクの枕カバーを購入してください

パデュー大学の教授が覚醒剤を扱った疑いで逮捕され、女性に性的好意を抱かせる

パデュー大学の教授が覚醒剤を扱った疑いで逮捕され、女性に性的好意を抱かせる

ラファイエット警察署は、「不審な男性が女性に近づいた」という複数の苦情を受けて、12 月にパデュー大学の教授の捜査を開始しました。

コンセプト ドリフト: AI にとって世界の変化は速すぎる

コンセプト ドリフト: AI にとって世界の変化は速すぎる

私たちの周りの世界と同じように、言語は常に変化しています。以前の時代では、言語の変化は数年または数十年にわたって発生していましたが、現在では数日または数時間で変化する可能性があります。

SF攻撃で91歳のアジア人女性が殴られ、コンクリートに叩きつけられた

犯罪擁護派のオークランドが暴力犯罪者のロミオ・ロレンゾ・パーハムを釈放

SF攻撃で91歳のアジア人女性が殴られ、コンクリートに叩きつけられた

認知症を患っている 91 歳のアジア人女性が最近、47 番街のアウター サンセット地区でロメオ ロレンゾ パーハムに襲われました。伝えられるところによると、被害者はサンフランシスコの通りを歩いていたところ、容疑者に近づき、攻撃を受け、暴行を受けました。

ℝ

“And a river went out of Eden to water the garden, and from thence it was parted and became into four heads” Genesis 2:10. ? The heart is located in the middle of the thoracic cavity, pointing eastward.

メリック・ガーランドはアメリカに失敗しましたか?

バイデン大統領の任期の半分以上です。メリック・ガーランドは何を待っていますか?

メリック・ガーランドはアメリカに失敗しましたか?

人々にチャンスを与えることは、人生で少し遅すぎると私は信じています。寛大に。

Language