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


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

私の小さなPHPプロジェクトでは、通常、手続き型の方法を使用します。私は通常、システム構成を含む変数を持っており、関数でこの変数にアクセスする必要がある場合は、そうしますglobal $var;

これは悪い習慣ですか?


19
グローバル変数は、悪い習慣の同義語である
L̳o̳̳n̳̳g̳̳p̳o̳̳k̳̳e̳̳


2
ユニット/受け入れテストを試してみると、グローバルが問題である理由がすぐにわかります。グローバルは、複数回実行するとコードの信頼性が低下します。
kzqai 2015年

回答:


102

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

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

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

詳細については、コールバックを参照してください。

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

さまざまな言語の標準や構成をPHPに適用することについて過度に心配する必要はありません。もう1つのよくある落とし穴は、オブジェクトモデルをすべての上に貼り付けることによって、PHPを純粋なOOP言語に変えようとすることです。

他のものと同様に、「グローバル」変数、手続き型コード、特定のフレームワーク、およびOOPを使用します。これは、理にかなっており、問題を解決し、作成する必要のあるコードの量を減らし、保守しやすく、理解しやすくするためです。あなたがすべき。


8
PHP 5.3は、ラムダ関数を使用してこの一部に対処しているため、コールバックのグローバルスコープで宣言された関数の使用を回避できることに注意してください。保守し、読み取り可能なコードのアドバイスのための1
ジョナサンFingland

array ($obj, 'callbackMethod')呼び出しでフォームのコールバックを使用できませんpreg_replace_callback()か?(私はこのOOPの落とし穴の餌食になりました...)
Grossvogel 2010

25
問題は「グローバル変数を使用すべきか」ではありませんでした。その答えは、「必要に応じて時々確認する」です。問題は、彼らが悪い習慣であるということです。答えは「はい、時々」です。ポスターの小さなプロジェクトの場合、悪いことは何も起こりませんが、チームメンバーが多く、可動部分が多い大規模なプロジェクトの場合、グローバル変数を多用すると、コードのデバッグが困難になり、リファクタリングがほぼ不可能になり、さらには苦痛になります。読んだ。あなたは時々それらを使うことができますか、..確かに-彼らはキナ吸うのですか、..ええ!
eddiemoya 2012

@eddiemoyaよく言ったエディ。グローバル変数の使用のような悪い習慣を正当化する人はとてもたくさんいます。あなたは疫病のようにそれらを避けるべきです。どんなまともなソフトウェア工学の学位もこれをあなたに掘り下げます...講師はそれの地獄についてあなたに言っているだけではありません...彼らは数十年の経験から知っています。必要な値にアクセスするには、可能な場合はメンバー関数を使用する必要があります。たとえば、Wordpressなどのget_query_var()

27

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

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

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

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


しかし、エラーは主にスクリプトが壊れているファイル/行を示しています。ここでは問題は見られません
samayo 2013

8
スクリプトが壊れた場所!=間違いがあった場所。
HonoredMule 2015年

16

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

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

よろしく、ドン


1
ええ、私は常にグローバルに使用する予定の変数にアンダースコアを付けます。
KRTac 2009年

9
@KRTacですが、$ _ testVariableは通常、プライベート変数であると理解されています。これは、グローバル変数ではなく、プライベート変数を定義するための非公式の標準です。
Aditya MP 2011年

6
一般的な方法は、すべて大文字を使用してグローバル変数を定義することです。例:$DB = 'foo';
pixeline 2015年

7

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

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

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

一般的に、グローバル変数を使用することは悪い習慣だとは言いません。プログラムのグローバル領域外でグローバル変数(フラグなど)を使用することは、問題を引き起こし、(長期的には)状態を簡単に追跡できなくなる可能性があるため、お勧めできません。また、学習すればするほど、グローバル変数への依存度が低くなります。これは、グローバル変数の使用に関連するバグを追跡する「喜び」を体験できるためです。これだけで、同じ問題を解決する別の方法を見つけるように促されます。偶然にも、これはPHPの人々を名前空間とクラス(静的メンバーなど)の使用方法を学ぶ方向に押しやる傾向があります。

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

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


3

終了したSOドキュメンテーションベータから再投稿

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

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

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

どこ$bobから来たの?

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

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

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

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

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


$ bobをどこにでも渡す必要がある代わりに、クラスBarをシングルトンにし、BarのインスタンスをBar自体に静的に格納し、静的メソッドを使用してオブジェクトをインスタンス化/フェッチすることもできます。そう$bob = Bar::instance();すれば、必要なときにいつでもできます。
スクーツ2017

1
シングルトンはアンチパターンと見なされることに注意してください。依存性注入はこれらの落とし穴を回避します
–Machavity

2
あなたがリンクしたその投稿内にはある程度の論争があり(たとえば、受け入れられた回答に対する最高評価のコメントと2番目に賛成された回答の両方が受け入れられた回答に強く反対しています)、シングルトンの使用はすべきであると主張する傾向があります手に負えない状態でまとめて却下されるのではなく、ケースバイケースで検討されます。
スクーツ2017

0

なので:

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

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

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

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

PHPエラーですが:

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

エラーではありませんハイフンは、のような「一般的な」ユーザー宣言変数と衝突ません$pagenow。また、大文字を使用すると、スーパーグローバルが使用されていること、コードで簡単に見つけられること、ファイル内検索して追跡できることを示します

次のように、単一のソリューションのすべてのクラスを構築するのが面倒な場合は、ハイフンを使用します。

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

しかし、より広い使用のケースでは、私が使っONE配列としてグローバルを:

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

後者は私にとって、データを「キャッシュ」するために毎回シングルトンクラスで乱雑にするのではなく、「コーラライト」の目的または使用に関するグッドプラクティスです。私が間違っているか、ここで愚かな何かを見逃している場合はコメントしてください...

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.