参考:変数スコープとは、どこからどの変数にアクセスできるのか、「未定義変数」エラーとは何ですか?
P粉018653751
2023-07-23 19:17:03
<p><br /></p><blockquote>
<p>注: これは、PHP で変数スコープを扱うための参考質問です。このパターンに当てはまる多くの質問を、この質問と重複するものとして閉じてください。</p>
</blockquote>
<p>PHP における変数スコープとは何ですか?ある .php ファイル内の変数に別のファイルからアクセスできますか?「未定義の変数」というエラー メッセージが表示される場合があるのはなぜですか?</p>
関数のスコープ内で定義された変数は外部からアクセスできませんが、関数の完了後にその値が使用できなくなるわけではありません。 PHP にはよく知られた static キーワードがあり、オブジェクト指向 PHP で静的メソッドとプロパティを定義するために広く使用されていますが、static キーワードは関数内で静的変数を定義するためにも使用できることを覚えておく必要があります。
静的変数は、関数のスコープ内で定義された通常の変数とは異なり、プログラムの実行がスコープの外に出ても値が失われません。静的変数を使用した次の例を考えてみましょう:
リーリー ###結果:### リーリー$counter 変数の定義に static キーワードを使用しない場合、毎回出力される値は関数に渡される $num パラメーターと同じになります。 static キーワードを使用すると、追加のソリューションを必要とせずに、この単純なカウンターを構築できます。
静的変数の目的
連続する関数呼び出しの間に値を保存するために使用されます。静的変数は、スカラーまたはスカラー式としてのみ定義できます (PHP 5.6 以降)。他の値を代入すると、少なくともこの記事の執筆時点では必ずエラーが発生します。ただし、次のコード行でこれを行うことができます:
リーリー ###結果:### リーリー静的関数は、同じクラスのオブジェクト メソッド間の「共有」メカニズムです。次の例を見ると簡単に理解できます:
リーリーこれは、同じクラスのオブジェクトに対してのみ機能します。オブジェクトが異なるクラスに属している場合 (たとえ相互に拡張していたとしても)、静的変数は期待どおりに動作します。
静的変数は関数呼び出し間で値を維持する唯一の方法ですか?関数呼び出し間で値を維持するもう 1 つの方法は、クロージャを使用することです。クロージャは PHP 5.3 で導入されました。簡単に言うと、特定の変数セットへのアクセスを、関数のスコープ内の別の匿名関数に制限できます。これが、それらの変数にアクセスする唯一の方法になります。クロージャ内では、変数は、オブジェクト指向プログラミングの「クラス定数」(値によってクロージャに渡される場合) または「プライベート プロパティ」(参照によって渡される場合) の概念を (多かれ少なかれうまく) エミュレートできます。 実際、後者では静的変数の代わりにクロージャを使用できます。どのメソッドを使用するかは完全に開発者の決定次第ですが、静的変数は再帰を扱うときに非常に便利であり、開発者の注目に値することは言及する価値があります。
変数スコープとは
変数の「スコープ」、つまり「アクセスできる場所」は限られています。アプリケーションのどこかで $foo = 'bar'; と書いたからといって、アプリケーションの他の場所で $foo を参照できるわけではありません。変数 $foo は特定のスコープ内で有効であり、同じスコープ内のコードによってのみアクセスできます。
PHP でスコープを定義するにはどうすればよいですか?
非常に簡単: PHP には関数スコープがあります。これは、PHP に存在する唯一のスコープ区切り文字です。関数内の変数は、その関数内でのみ使用できます。関数の外側の変数は関数の外側のどこでも使用できますが、関数の内部では使用できません。これは、PHP にはグローバル スコープという特別なスコープがあることを意味します。関数の外で宣言された変数はグローバル スコープ内にあります。
###例えば:### リーリー $fooは
global
スコープ内にあり、$baz はmyFunc
内の local スコープ内にあります。myFunc
内のコードのみが$baz
にアクセスできます。コードoutside
myFunc のみが$foo
にアクセスできます。どちらも他方にアクセスできません:リーリー
スコープと含まれるファイルファイル境界はスコープを分離しません。
a.phpリーリー
b.phpリーリー インクルードされたコードに適用されるルールは、他のコードに適用されるルールと同じです。スコープを分離できるのは関数のみです。スコープの観点からは、インクルード ファイルはコードのコピー アンド ペーストと考えることができます。
c.phpリーリー 上記の例では、a.php は myFunc 内に含まれており、a.php 内の変数はローカル関数スコープのみを持ちます。 a.php でグローバルにスコープ設定されているように見えるからといって、実際にスコープが設定されているとは限りません。実際には、そのコードが含まれる/実行されるコンテキストによって異なります。
関数と関数内のクラスに関して、別の状況に対処するにはどうすればよいですか?
新しい関数の宣言ごとに新しいスコープが導入されます。これは非常に簡単です。
関数内の(匿名) 関数。
リーリー ###親切### リーリースコープの用途は何ですか?
スコープの問題に対処するのは面倒に思えるかもしれませんが、変数のスコープを制限することは、複雑なアプリケーションを作成する上で非常に重要です。アプリケーションで宣言したすべての変数にどこからでもアクセスできる場合、変数への変更を追跡できなくなります。変数には限られた数の適切な名前しか付けることができず、変数 "$name" を複数の場所で使用することもできます。アプリケーション内で一意の変数名を 1 つしか持てない場合は、変数の一意性を確保し、間違ったコード部分から間違った変数を変更しないようにするために、非常に複雑な命名スキームを使用する必要があります。
###次のように:### リーリースコープがない場合、上記の関数は何をするのでしょうか? $bar はどこから来たのでしょうか?それはどのようなステータスを持っていますか?初期化されてるのかな?毎回確認する必要がありますか?これは保守不可能です。これはにつながります...###
スコープの境界を越えるリーリー
変数 $bar は、関数パラメーターとしてスコープに明示的に渡されます。この関数を見るだけで、使用する値がどこから来たのかは明らかです。次に、明示的に値を返します。呼び出し元は、関数がどの変数を使用するのか、戻り値がどこから来たのかを確認できます。 リーリー変数のスコープを無名関数に拡張する
リーリー匿名関数には、周囲のスコープから $foo 変数が明示的に含まれます。これはグローバル スコープとは異なることに注意してください。
間違った方法:
グローバル
前に述べたように、グローバル スコープは特別であり、関数はグローバル スコープから変数を明示的にインポートできます。 リーリー
この関数は、グローバル変数 $foo を使用および変更します。こんなことしないで! (自分が何をしているのか本当に本当に理解している場合を除き、たとえそうであったとしても、それはやめてください!)リーリー
この関数には副作用があるという兆候はありませんが、実際には副作用があります。一部の関数が常に変更され、グローバルな状態に依存している場合、これは簡単に厄介な状況になる可能性があります。関数をステートレスにして、呼び出し回数に関係なく、入力のみで動作し、定義された出力を返すようにします。