web-dev-qa-db-ja.com

PHPのグローバル変数は悪い習慣と見なされていますか?そうであれば、なぜですか?

function foo () {
    global $var;
    // rest of code
}

私の小さなPHPプロジェクトでは、通常、手順を踏んでいます。通常、システム構成を含む変数があり、関数でこの変数にアクセスする必要があるときは、global $var;

これは悪い習慣ですか?

84
KRTac

人々が他の言語でグローバル変数について話すとき、それはPHPで行うものとは異なる何かを意味します。これは、変数がPHPで本当にグローバルではないためです。通常のPHPプログラムは1つのHTTPリクエストです。セッション変数は、多くのHTTPリクエストを含むため、実際にはPHP "global"変数よりも広いスコープを持っています。 。

多くの場合(常に?)、次のようにpreg_replace_callback()のようなメソッドでメンバー関数を呼び出すことができます。

preg_replace_callback('!pattern!', array($obj, 'method'), $str);

詳細については、 callbacks を参照してください。

要点は、オブジェクトがPHPにボルトで固定されており、ある意味で厄介なことにつながることです。

さまざまな言語の標準や構成をPHPに適用することを過度に心配しないでください。別の一般的な落とし穴は、オブジェクトモデルをすべての上に貼り付けることでPHPを純粋なOOP言語に変えることです。

他のすべてと同様に、「グローバル」変数、手続き型コード、特定のフレームワークを使用し、OOP意味があるため、問題を解決し、記述する必要のあるコードの量を減らすか、保守性を高めますそして、あなたがすべきだと思うからではなく、理解しやすい。

98
cletus

グローバル変数を慎重に使用しないと、問題を見つけにくくなります。 phpスクリプトをリクエストすると、ある関数に存在しない配列のインデックスにアクセスしようとしているという警告が表示されたとします。

アクセスしようとしている配列が関数に対してローカルである場合、関数をチェックして、そこで間違いを犯していないかどうかを確認します。関数への入力に問題がある可能性があるため、関数が呼び出される場所を確認します。

しかし、その配列がグローバルである場合、そのグローバル変数を使用するすべての場所を確認する必要があり、それだけでなく、グローバル変数への参照がアクセスされる順序を把握する必要があります。

コードの一部にグローバル変数がある場合、そのコードの機能を分離するのが難しくなります。なぜ機能を分離したいのですか?したがって、それをテストし、他の場所で再利用できます。テストする必要がなく、再利用する必要のないコードがある場合は、グローバル変数を使用しても問題ありません。

27
rojoca

私はクレトスに同意します。私は2つのことを追加します:

  1. プレフィックスを使用して、すぐにグローバルとして識別できるようにします(例:$ g_)
  2. それらを1つの場所で宣言し、コード全体に散らばらないでください。

よろしく、ドン

16
Don Dickinson

経験、大学の学位、ソフトウェアエンジニアリングに反対できるのは誰ですか?私じゃない。オブジェクト指向の単一ページPHP applicatonsを開発するとき、名前空間の衝突を心配することなくすべてをゼロから構築できることを知ったとき、私はもっと楽しくなります。多くの人はもうしません。仕事、締め切り、ボーナス、または気にする評判があります。これらのタイプは、大掛かりな事前構築コードを使用する傾向があるため、グローバル変数を使用するリスクはまったくありません。

グローバル変数をプログラムのグローバル領域でのみ使用する場合でも、グローバル変数を使用するのは悪いかもしれませんが、ただ楽しみを持ち、何かを機能させるだけをしたい人は忘れないでください。

それがグローバル名前空間でいくつかの変数(<10)を使用することを意味する場合、それはプログラムのグローバル領域でのみ使用されます。はい、はい、MVC、依存性注入、外部コード、何とか、何とか、何とか、何とか。ただし、コードの99.99%を名前空間とクラスに含め、外部コードがサンドボックス化されている場合、グローバル変数を使用すると、世界は終了しません(繰り返しますが、世界は終了しません)。

一般的に、グローバル変数の使用は悪い習慣とは言いません。プログラムのグローバル領域の外側でグローバル変数(フラグなど)を使用することは、トラブルを要求するおよび(長期的には)不適切なアドバイスであると言います。かなり簡単に状態を追跡できなくなります。また、学習すればするほど、信頼性は低くなりますグローバル変数については、その使用に関連するバグを追跡する「喜び」を経験するためです。これだけでも、同じ問題を解決する別の方法を見つける動機になります。偶然にも、これはPHP名前空間とクラス(静的メンバーなど...)の使用方法を学ぶ方向に人々をプッシュする傾向があります。

コンピュータサイエンスの分野は広大です。 badとラベル付けしているので、誰もが何かをするのを怖がらせると、ラベルの背後にある理由を真に理解する楽しさを失います。

必要な場合はグローバル変数を使用しますが、グローバル変数がなくても問題を解決できるかどうかを確認します。衝突、テスト、およびデバッグは、問題の説明だけでなく、問題の本質を密接に理解することを意味します。

5

終了したSO Documentation Betaから再投稿

次の擬似コードでこの問題を説明できます

_function foo() {
     global $bob;
     $bob->doSomething();
}
_

ここでの最初の質問は明らかです

_$bob_はどこから来たのですか?

混乱していますか?良い。グローバルが混乱している理由を学習したばかりで、悪い習慣と見なされています。これが実際のプログラムである場合、次の楽しみは_$bob_のすべてのインスタンスを追跡し、正しいインスタンスを見つけることです(_$bob_がどこでも使用されている場合、これはさらに悪化します)。さらに悪いことに、誰かが_$bob_(またはその変数を忘れて再利用した)を定義すると、コードが壊れる可能性があります(上記のコード例では、間違ったオブジェクトがあるか、オブジェクトがまったくないために致命的なエラーが発生します) 。事実上すべてのPHP=プログラムはinclude('file.php');のようなコードを使用するため、このようなコードを維持する仕事は、ファイルを追加するほど指数関数的に難しくなります。

グローバルを回避するにはどうすればよいですか?

グローバルを回避する最良の方法は、依存性注入と呼ばれる哲学です。ここで、必要なツールを関数またはクラスに渡します。

_function foo(\Bar $bob) {
    $bob->doSomething();
}
_

これはmuch理解と保守が簡単です。 _$bob_が設定されている場所を推測することはできません。これは、呼び出し側がそれを知る責任があるためです(知る必要があるものを渡しているため)。さらに良いことに、 型宣言 を使用して、渡されるものを制限できます。したがって、_$bob_はBarクラスのインスタンス、またはBarの子のインスタンスであることがわかります。つまり、そのクラスのメソッドを使用できることがわかります。標準のオートローダーと組み合わせて(PHP 5.3以降で利用可能)、Barが定義されている場所を追跡できます。PHP 7.0以降拡張型宣言が含まれます。スカラー型(intstringなど)も使用できます。

2
Machavity

なので:

global $my_global; 
$my_global = 'Transport me between functions';
Equals $GLOBALS['my_global']

悪い習慣です(Wordpress $pagenow)...うーん

これを考慮してください:

$my-global = 'Transport me between functions';

is PHP errorしかし:

$GLOBALS['my-global'] = 'Transport me between functions';

[〜#〜] not [〜#〜]エラー、hypensは「共通」ユーザー宣言変数と衝突しません 、 お気に入り $pagenow。また、大文字を使用すると、使用中のスーパーグローバル、コード内で簡単に見つけられる、またはファイル内でfindで追跡しやすいことを示します

私が怠laな場合は、ハイフンを使用して、単一のソリューションのすべてのクラスを構築します:

$GLOBALS['PREFIX-MY-GLOBAL'] = 'Transport me ... ';

しかし、もっと広く使用する場合は、[〜#〜] one [〜#〜] globals as array:

$GLOBALS['PREFIX-MY-GLOBAL']['context-something'] = 'Transport me ... ';
$GLOBALS['PREFIX-MY-GLOBAL']['context-something-else']['numbers'][] = 'Transport me ... ';

後者は私にとっては、良い習慣であり、データを「キャッシュ」するために毎回シングルトンクラスで混乱するのではなく、「コーラライト」の目的または使用です。私が間違っているか、ここで愚かな何かが欠落している場合はコメントをしてください...

0
Jonas Lundman