PHPグローバル関数


100

グローバルキーワードのユーティリティは何ですか?

ある方法を別の方法よりも好む理由はありますか?

  • セキュリティ?
  • パフォーマンス?
  • 他に何か?

方法1:

function exempleConcat($str1, $str2)
{
  return $str1.$str2;
}

方法2:

function exempleConcat()
{
  global $str1, $str2;
  return $str1.$str2;
}

いつ使用するのが意味がありますglobalか?

私にはそれは危険なように見えます...しかし、それは単に知識の欠如かもしれません。文書化された(例:コードの例、ドキュメントへのリンクなど)技術的な理由に興味があります

前もって感謝します!


バウンティ

これはトピックに関する一般的な質問です。私(@Gordon)は、追加の回答を得るための賞金を提供しています。あなたの答えが私の意見に一致するかどうか、または別の見方をするかどうかは問題ではありません。globalトピックが時々出てくるので、リンクするのに良い「標準的な」答えを使うことができました。


2
このリンクを ご覧ください:stackoverflow.com/questions/1557787このページの右下に関連記事がたくさんあります
JohnP

それはあなたの質問への直接の答えではありませんが、この古いSO質問を読んでください
オラフルWaage

1
そのため、私はプログローバルキーワードを読み取ることができません。1)なぜここにあるのか。2)なぜ人々はそれを使うのですか?
Pascal Qyy、2011年

@ G.Qyyなぜそこにあるのgotoですか?なぜ人々はそれを使うのですか?彼らはそれを使わない(少なくとも私は願っています):P
PeeHaa

昨年末(12月14日)に誰かがこの質問に反対票を投じました。ネガティブなものも含めて、すべての視点が興味深いので、その理由を知りたいと思っています。この場合、これまで以上に!私はそれについての手がかりを非常に感謝します。
Pascal Qyy 2015

回答:


158

グローバルは悪です

これは、globalキーワードだけでなく、ローカルスコープからグローバルスコープ(静的、シングルトン、レジストリ、定数)に到達する他のすべてにも当てはまります。あなたはそれらを使いたくないのです。関数呼び出しは、外部のものに依存する必要はありません。たとえば、

function fn()
{
    global $foo;              // never ever use that
    $a = SOME_CONSTANT        // do not use that
    $b = Foo::SOME_CONSTANT;  // do not use that unless self::
    $c = $GLOBALS['foo'];     // incl. any other superglobal ($_GET, …)
    $d = Foo::bar();          // any static call, incl. Singletons and Registries
}

これらはすべて、コードを外部に依存させることになります。つまり、これらのいずれかを確実に呼び出す前に、アプリケーションの完全なグローバル状態を知る必要があります。その環境がなければ、関数は存在できません。

スーパーグローバルの使用は明らかな欠陥ではないかもしれませんが、コマンドラインからコードを呼び出す場合、$_GETまたははありません$_POST。コードがこれらからの入力に依存している場合、Web環境に制限されています。リクエストをオブジェクトに抽象化し、代わりにそれを使用します。

ハードコードされたクラス名(静的、定数)を結合する場合、そのクラスが利用可能でなければ、関数も存在できません。同じ名前空間からのクラスの場合はそれほど問題ではありませんが、異なる名前空間からミックスを開始すると、複雑な混乱が生じます。

上記のすべてが再利用を妨げている。ユニットテストもそうです

また、グローバルスコープに結合すると、関数のシグネチャは嘘をつきます

function fn()

嘘つきです。何も渡さなくてもその関数を呼び出せるからです。関数本体を見たときに初めて、環境を特定の状態に設定する必要があることがわかります。

関数の実行に引数が必要な場合は、引数を明示的にして渡します。

function fn($arg1, $arg2)
{
    // do sth with $arguments
}

シグネチャから、呼び出す必要があることを明確に伝えます。特定の状態になるかどうかは、環境に依存しません。あなたがする必要はありません

$arg1 = 'foo';
$arg2 = 'bar';
fn();

これは、(グローバルキーワード)を引き込むか、(引数)を押し込むかの問題です。依存関係をプッシュ/インジェクトすると、関数は外部に依存しなくなります。その場合fn(1)、1を外部に保持する変数を持つ必要はありません。ただし$one、関数内でグローバルをプルすると、グローバルスコープに結合し、どこかで定義された変数の変数があることを期待します。その場合、機能はもはや独立していません。

さらに悪いことに、関数内でグローバルを変更する場合、関数は至る所に副作用があるため、コードはすぐに完全に理解できなくなります。

より良い例がない場合は、

function fn()
{
    global $foo;
    echo $foo;     // side effect: echo'ing
    $foo = 'bar';  // side effect: changing
}

そして、あなたはします

$foo = 'foo';
fn(); // prints foo
fn(); // prints bar <-- WTF!!

$fooこれらの3行から変更されたことを確認する方法はありません。出力が突然変化したり、グローバル状態の値が変化したりして、同じ関数を同じ引数で呼び出すのはなぜですか?関数は、定義された入力Yに対してXを実行する必要があります。常に。

OOPはカプセル化に関するものであり、グローバルスコープに到達することにより、カプセル化を解除しているため、OOPを使用する場合、これはさらに深刻になります。フレームワークに表示されるこれらすべてのシングルトンとレジストリは、依存性注入を優先して削除する必要があるコードのにおいです。コードを分離します。

その他のリソース:


10
なぜPHPはそのようなものを実装するのですか?ユーティリティはありますか?多くの人が毎回使用するPHPの危険な実装にいつも驚いています...論理的な理由がないとは信じがたいことです。
Pascal Qyy 2011年

5
Globalsをより悪に大きくすることができれば幸いです。
Kermit 2013

3
うわー、ようやく誰かがグローバルが悪である理由をよく説明しました...私はいつもそうだったといつも聞いていて、理由について非常に具体的な例をいくつか見ましたが、これは一般的な理由の本当に良い包括的な説明です。+1
ウィングブレード2013

私は本当に遅れており、私はあなたの言っていることを理解していますが、mysqli接続はどうですか?それらが毎回パラメーターとして渡されるか、グローバル$ linkである必要があります。あなたの目に許されますか?
2013年

2
定数を除いて、あなたは正しいです。これらはアプリケーションの「状態」を表すものではなく、関数内から参照することは問題ありません。内部から定数を使用している場合、関数は「嘘」をつきません。ある時点でプログラマーが外部についての知識を持っていたことを意味することに同意しますが、それは定数が何であるかについての非常に許容できるトレードオフです。また、真剣に、それはあまり大きな取引ではありません。
セバス

35

大きな理由の1つglobalは、関数が別のスコープに依存していることを意味します。これは非常に早く混乱します。

$str1 = 'foo';
$str2 = 'bar';
$str3 = exampleConcat();

$str = exampleConcat('foo', 'bar');

必要$str1$str2不必要な依存関係を導入し、作業手段への機能を呼びかける範囲で設定されます。このスコープでこれらの変数の名前を変更するには、関数でそれらの名前を変更する必要があります。そのため、この関数を使用している他のすべてのスコープでも同じです。変数名を追跡しようとしているため、これはすぐに混乱に発展します。

global$dbリソースなどのグローバルなものを含める場合でも、悪いパターンです。そこになる名前を変更する際の日に来る$dbが、あなたのアプリケーション全体が名前に依存するため、できません。

変数のスコープを制限および分離することは、途中の複雑なアプリケーションを作成するために不可欠です。


1
申し訳ありませんが、なぜ名前を変更したいの$dbですか?それはどこにでも渡されるPDOです。接続情報を個別に更新できるのになぜ変更されるのですか?
Casey Dwayne

3
@kcdある日、依存関係の注入がいかに素晴らしいかを理解し、アプリを再構築したいのですか?そのため1日のあなたには、いくつかの他のものを自分のものを統合する必要がありますまた、グローバル使用する$db変数を?ある日、ユニットテストを発見し、そのために一度に複数のデータベース接続を管理する必要があるからですか?多くの理由があります。
だます

35

グローバルは避けられません。

それは古い議論ですが、上記の回答でそれらを逃したので、私はまだいくつかの考えを追加したいと思います。これらの回答は、グローバルが多すぎることを単純化し、問題の解決策ではない解決策を提示します。問題は、グローバル変数とキーワードグローバルの使用を処理する適切な方法は何ですか?そのためには、まずグローバルとは何かを調べて説明する必要があります。

このZendのコードを見てください。Zendの記述が不適切であることはお勧めしません。

class DecoratorPluginManager extends AbstractPluginManager
{
/**
 * Default set of decorators
 *
 * @var array
 */
protected $invokableClasses = array(
    'htmlcloud' => 'Zend\Tag\Cloud\Decorator\HtmlCloud',
    'htmltag'   => 'Zend\Tag\Cloud\Decorator\HtmlTag',
    'tag'       => 'Zend\Tag\Cloud\Decorator\HtmlTag',
   );

ここには目に見えない依存関係がたくさんあります。これらの定数は実際にはクラスです。このフレームワークの一部のページでrequire_onceも確認できます。Require_onceはグローバルな依存関係であるため、外部依存関係を作成します。それはフレームワークにとって避けられないことです。依存する多くの外部コードなしで、DecoratorPluginManagerのようなクラスをどのように作成できますか?それは多くの追加なしでは機能しません。Zendフレームワークを使用して、インターフェースの実装を変更したことがありますか?インターフェースは実際にはグローバルです。

グローバルに使用されているもう1つのアプリケーションはDrupalです。彼らは適切な設計に非常に関心がありますが、他の大きなフレームワークと同じように、多くの外部依存関係があります。このページのグローバルをご覧ください。

/**
 * @file
 * Initiates a browser-based installation of Drupal.
 */

/**
 * Root directory of Drupal installation.
 */
define('DRUPAL_ROOT', getcwd());

/**
 * Global flag to indicate that site is in installation mode.
 */
define('MAINTENANCE_MODE', 'install');

// Exit early if running an incompatible PHP version to avoid fatal errors.
if (version_compare(PHP_VERSION, '5.2.4') < 0) {
  print 'Your PHP installation is too old. Drupal requires at least PHP 5.2.4. See the     <a     href="http://drupal.org/requirements">system requirements</a> page for more     information.';
  exit;
}

// Start the installer.
require_once DRUPAL_ROOT . '/includes/install.core.inc';
install_drupal();

ログインページへのリダイレクトを作成したことがありますか?それはグローバルな価値観を変えています。(そして、あなたは 'WTF'とは言っていません。これは、アプリケーションの不適切なドキュメントに対する良い反応だと私は考えています。)グローバルの問題は、それらがグローバルであることではなく、意味のあるアプリケーションを得るために必要です。問題は、アプリケーション全体の複雑さであり、処理するのが悪夢になります。セッションはグローバル、$ _ POSTはグローバル、DRUPAL_ROOTはグローバル、includes / install.core.inc 'は変更不可能なグローバルです。機能を機能させるために必要な機能の外側には大きな世界があります。

ゴードンの答えは正しくありません。なぜなら、彼は関数の独立性を過大評価し、関数を嘘つきと呼ぶことは状況を単純化しすぎているからです。関数は嘘をつかないので、彼の例を見てみると、関数は正しく設計されていません-彼の例はバグです。(ちなみに、コードを分離する必要があるという私はこの結論に同意します。)decezeの答えは、実際には状況の適切な定義ではありません。関数は常により広い範囲内で機能し、彼の例はあまりにも単純化しています。定数を返すので、その関数は完全に役に立たないということは、私たち全員が同意します。その機能はとにかく悪いデザインです。練習が悪いことを示したい場合は、適切な例を挙げてください。アプリケーション全体で変数の名前を変更することは、優れたIDE(またはツール)を使用することで大したことではありません。問題は変数のスコープについてであり、関数とスコープの違いではありません。関数がプロセスでその役割を実行するための適切な時間があります(そのため、最初に関数が作成されます)。その適切な時に、アプリケーション全体の機能に影響を与える可能性があり、グローバル変数にも作用します。xzyferの答えは、引数のないステートメントです。手続き型関数やOOP設計がある場合、グローバルはアプリケーションに存在します。グローバルの値を変更する次の2つの方法は基本的に同じです。したがって、グローバル変数にも取り組んでいます。xzyferの答えは、引数のないステートメントです。手続き型関数やOOP設計がある場合、グローバルはアプリケーションに存在します。グローバルの値を変更する次の2つの方法は基本的に同じです。したがって、グローバル変数にも取り組んでいます。xzyferの答えは、引数のないステートメントです。手続き型関数やOOP設計がある場合、グローバルはアプリケーションに存在します。グローバルの値を変更する次の2つの方法は基本的に同じです。

function xzy($var){
 global $z;
 $z = $var;
}

function setZ($var){
 $this->z = $var;
}

どちらの場合も、特定の関数内で$ zの値が変更されます。どちらのプログラミング方法でも、コードの他の多くの場所でこれらの変更を行うことができます。グローバルを使用すると、どこでも$ zを呼び出してそこで変更できると言えます。はい、できます。しかし、あなたはしますか?そして、不適切な場所で行われた場合、それはバグと呼ばれるべきではありませんか?

Bob Fangerがxzyferについてコメントしています。

だれでも、特に「グローバル」というキーワードだけを使用する必要がありますか?いいえ。ただし、他の種類のデザインと同様に、それが何に依存し、何に依存するかを分析してください。それがいつ変化し、どのように変化するかを調べてください。グローバル値の変更は、すべての要求/応答で変更できる変数でのみ発生する必要があります。つまり、プロセスの機能フローに属する変数のみであり、その技術的な実装には属していません。ログインページへのURLのリダイレクトは、技術的な実装へのインターフェイスに使用される実装クラスであるプロセスの機能フローに属します。後者はアプリケーションの異なるバージョンの間に変更できますが、すべての要求/応答でそれらを変更するべきではありません。

グローバルとキーワードグローバルの操作に問題がある場合とそうでない場合をさらに理解するために、ブログについて書くときにWim de Bieからの次の文を紹介します。「個人的はい、私的いいえ」。関数が自身の機能のためにグローバル変数の値を変更している場合、そのグローバル変数のプライベート使用とバグを呼び出します。しかし、ユーザーのログインページへのリダイレクトのように、アプリケーション全体の適切な処理のためにグローバル変数の変更が行われた場合、それは私の考えではおそらく良い設計であり、定義上悪いわけではなく、アンチパターン。

Gordon、deceze、xzyferの回答を振り返ってみると、例としてすべて 'private yes'(およびバグ)があります。それが彼らがグローバルの使用に反対している理由です。私もします。ただし、私がこの回答で何度か行ったような「個人的はい、個人的いいえ」の例は付いていません。


Drupalコードサンプルはグローバルを使用せず、定数を使用します。非常に重要な違いは、一度定義された定数は再定義できないことです。また、関数xyzとを比較することもできませんsetZ。最初はグローバル状態を変更し、2番目はクラスメソッドであり、呼び出されたインスタンスの状態のみを変更します。
Arjan、2014年

@Arjen:Drupal 7.14でキーワードglobalを検索すると、何百ものヒットが得られます。これはパブリックセッターの古い問題です。パブリックセッターを変更すると、変更された場所を制御できなくなります。それらをまったく使用しないか、プライベートとして宣言することをお勧めしているため、後で追加することはできません。
Loek Bergman

@Arjan:名前のつづりの間違いが原因で、あなたへの私の返答の通知を受け取りませんでした。今するでしょう。:-)
Loek Bergman、2014

@LoekBergman:globaldrupal 7.26(最新バージョン)の単語には約400のヒットがあり、それらのヒットの一部はコメントにあり、その他の何回かは何年も触れられていないコードにあるようです。私は、彼らが使用していないことを願っていますglobals内のDrupal 8
Arjan

@LoekBergmanセッターとゲッターを使用してください。設定に時間がかからず、コードを使用しているクラスを拡張して他のコントロールを強化できる可能性があります。パラメータを公開すると、それがそれになります。後で非表示にするオプションはありません。
mAsT3RpEE 2014

15

単純に言えばglobal、現代のPHPコードIMHOに理由があり、それが決して良いことではありません。特にPHP 5を使用している場合は特に、オブジェクト指向コードを開発している場合はさらに特別です。

グローバルは、コードの保守性、可読性、およびテスト容易性に悪影響を及ぼします。globalcanの多くの使用法は、Dependency Injectionに置き換えるか、単にグローバルオブジェクトをパラメーターとして渡す必要があります。

function getCustomer($db, $id) {
    $row = $db->fetchRow('SELECT * FROM customer WHERE id = '.$db->quote($id));
    return $row;
}

10

PHPの関数内でグローバルキーワードを使用することをためらわないでください。特に、グローバル化がいかに「悪」であり、何がそうではないかについて、風変わりに説教/叫び声を上げている人々を連れてはいけません。

まず、使用するものは状況と問題に完全に依存し、コーディングで何かを行うための1つの解決策/方法がないためです。「悪」のような定義できない、主観的な、宗教的な形容詞の誤りを完全に排除します。

適例 :

Wordpressとそのエコシステムは、機能にグローバルキーワードを使用しています。コードがOOPであるかどうか。

そして現在のところ、Wordpressは基本的にインターネットの18.9%であり、ロイターからソニー、NYT、CNNまでの無数の巨人の巨大なメガサイト/アプリを実行しています。

そしてそれはうまくいきます。

関数内でグローバルキーワードを使用すると、Wordpressは巨大なエコシステムを前提として発生するMASSIVE膨張から解放されます。すべての関数が別のプラグイン、コア、およびリターンから必要な変数を要求/渡していると想像してください。プラグインの相互依存性を追加すると、変数の悪夢、または変数として渡される配列の悪夢になってしまいます。追跡する地獄、デバッグする地獄、開発する地獄。コードの肥大化と変数の肥大化による、非常に大規模なメモリフットプリント。書くのも難しい。

Wordpress、そのエコシステム、彼らの慣行、そしてそれらの部分で何が起こっているかを批判し、批判する人々がいるかもしれません。

このエコシステムはインターネット全体のほぼ20%であるため、無意味です。どうやら、それは機能します、それはその仕事などを行います。これは、グローバルキーワードの場合も同じです。

もう1つの良い例は、「iframeは悪である」原理主義です。10年前、iframeを使用することは異端でした。そしてインターネット上で何千人もの人々が彼らに対して説教をしていました。その後、Facebookが登場し、ソーシャルが登場します。iframeは「いいね」ボックスから認証、そして出来上がりまでありとあらゆるところにあります。それでも黙ってなかった人たちがいます-正しくまたは間違って。しかし、あなたはそのような意見にもかかわらず、人生は続いています。10年前にiframeについて説教していた人々でさえ、今ではさまざまなソーシャルアプリを組織の独自のアプリケーションに統合するために、一言も言わずにそれらを使用する必要があります。

……

Coder Fundamentalismは非常に悪いものです。情報技術の絶え間ない変化とそれが競争、時間、予算、およびその他の考慮事項に関してもたらす圧力に耐える十分な影響力を持ち、したがって実践できる堅実なモノリシック企業での快適な仕事に恵まれている可能性があります。原理主義と知覚された「悪魔」または「商品」の厳格な遵守。占領者が若い場合でも、これらは古い時代を連想させる快適な位置です。

ただし、大多数にとって、ITの世界は常に変化し続ける世界であり、オープンマインドで実用的である必要があります。原理主義のための場所はありません。情報技術の最前線の溝に「悪」のようなとんでもないキーワードを残してください。

AT HANDの問題に最も適したものを使用し、近い将来、中長期の将来について適切に考慮してください。特定のコーダーサブセットの中で、それに対して蔓延しているイデオロギー的な敵意を持っているので、機能やアプローチの使用をためらわないでください。

彼らはあなたの仕事をしません。あなたはするであろう。状況に応じて行動してください。


3
アンチファンダメンタリズムなどの+1ですが、「多くの人がそれを使用する/機能する/など」と言うことは、単なる「論争の広告」、基本的な洗練です。大多数の人が1つのことを考えたり実行したりしても、それらが正しいことを証明しません!群衆の中で危険が現れると、大多数の人は愚かなことをし、一部の人は他人に踏みつけられ死んでしまいます。火災から逃れるために引かれた場合にのみ開くドアを絶対に押す必要があると考えているからといって、この5歳の少女の顔に足を置くのは正しいのでしょうか。私はそうは思いません…
Pascal Qyy

1
もちろん、大部分が何かを行うことは、それ自体では何も検証しません。ただし、ケースはソフトウェアです。そして、大多数がそれをやっていて、これらの人々によって作成されたアプリやサービスの大部分がうまく機能している場合(他の多くの人にとってはワードプレス)、それはそれらが使用できることを意味します。
unity100 2014年

7

私は誰もがグローバルの否定的な側面についてかなり説明してきたと思います。だから私はポジティブとグローバルの適切な使用のための指示を追加します:

  1. グローバルの主な目的は、機能間で情報を共有することでした。クラスのようなものが何もなかった頃、phpコードは多数の関数で構成されていました。場合によっては、機能間で情報を共有する必要があります。通常、これを行うためにグローバルを使用し、データをグローバルにするとデータが破損するリスクがありました。

    幸運な幸運なシンプルトンが依存関係の注入についてコメントを始める前に、例のような関数のユーザーが関数のget_post(1)すべての依存関係をどのようにして知っているかを尋ねたいと思います。また、依存関係は
    バージョンごと、サーバーごとに異なる場合があることを考慮してください。依存関係注入の主な問題は、依存関係を事前に知っておく必要があることです。これが不可能または望ましくないグローバル変数がこの目的を達成する唯一の方法であった状況では。

    クラスの作成により、共通の関数をクラスに簡単にグループ化してデータを共有できるようになりました。Mediatorのような実装により、関係のないオブジェクトでさえ情報を共有できます。これはもう必要ありません。

  2. グローバルのもう1つの用途は、構成の目的です。ほとんどの場合、オートローダーが読み込まれる前、データベース接続が作成される前など、スクリプトの最初です。

    リソースのロード中に、グローバルを使用してデータを構成できます(つまり、ライブラリファイルが配置されている場所で使用するデータベース、サーバーのURLなど)。define()これらの値は頻繁に変更されることはなく、構成ファイルに簡単に配置できるため、これを行う最良の方法は関数を使用することです。

  3. グローバルの最終的な用途は、一般的なデータ(CRLF、IMAGE_DIR、IMAGE_DIR_URL)、人間が読めるステータスフラグ(ITERATOR_IS_RECURSIVE)を保持することです。ここでグローバルは、アプリケーション全体で使用されることを意図した情報を格納するために使用され、それらを変更して、それらの変更をアプリケーション全体に表示します。

  4. シングルトンパターンは、オブジェクトの各インスタンスがメモリを占有するphp4の間にphpで人気が出ました。シングルトンは、オブジェクトのインスタンスを1つだけ作成できるようにすることで、RAMの節約に役立ちました。参照の前に、依存性注入さえも悪い考えだったでしょう。

    PHP 5.4以降のオブジェクトの新しいphp実装は、ほとんどまたはまったくペナルティなしでオブジェクトを安全に渡すことができるこれらの問題のほとんどを処理します。これはもう必要ありません。

    シングルトンのもう1つの使用法は、オブジェクトのインスタンスが一度に1つだけ存在する必要がある特別なインスタンスであり、そのインスタンスはスクリプト実行の前後に存在し、そのオブジェクトは異なるスクリプト/サーバー/言語などで共有されます。ここで、シングルトンパターンは非常によくソリューション。

したがって、結論として、1、2、または3の位置にいる場合は、グローバルを使用するのが妥当です。ただし、他の状況では、方法1を使用する必要があります。

グローバルを使用する必要がある他のインスタンスを自由に更新してください。


6

globalキーワードを使用してconcat関数を作成しても意味がありません。

データベースオブジェクトなどのグローバル変数にアクセスするために使用されます。

例:

function getCustomer($id) {
  global $db;
  $row = $db->fetchRow('SELECT * FROM customer WHERE id = '.$db->quote($id));
  return $row;
}

シングルトンパターンのバリエーションとして使用できます。


「意味がありません」-実際にはそうです。例として、OOPを使用せずにルックアップテーブルを実装します。
Nir Alfasi
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.