1. ホーム
  2. php

[解決済み] 関数内のPHPグローバル

2023-01-25 15:30:20

質問

の効用は何でしょうか? グローバルキーワード ?

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

  • セキュリティ?
  • パフォーマンス?
  • その他は?

方法1:

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

方法2

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

どのような場合に global ?

私の場合、それは は危険に見える ... でも、それは単なる知識不足かもしれません。 私が興味を持ったのは 文書化された (例:コードの例、ドキュメントへのリンク...) 技術的な理由に興味があります。

事前にありがとうございます!


懸賞金

これはこのトピックに関する素晴らしい一般的な質問です。私 (@Gordon) は追加の回答を得るために懸賞金を提供します。あなたの回答が私の回答と一致するか、あるいは異なる視点を提供するかは重要ではありません。というのも global のトピックは時々出てくるので、私たちはリンクするために良い "canonical"の答えを使うことができます。

どのように解決するのですか?

グローバルは悪である

これは 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();

pull in (グローバルキーワード) vs push in (引数)の問題です。依存関係をプッシュ・イン/インジェクションすると、その関数はもう外部に依存しなくなります。あなたが 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 が変更されたことを確認する方法はありません。なぜ同じ関数を同じ引数で呼び出すと、突然出力が変わったり、グローバルな状態の値が変わったりするのでしょうか?関数は定義された入力 Y に対して X を実行する必要があります。

なぜなら、OOPはカプセル化についてであり、グローバルスコープに手を伸ばせば、カプセル化を破ることになるからです。フレームワークで見られるこれらのシングルトンやレジストリはすべて、依存性注入を優先して削除されるべきコード臭です。コードをデカップリングしましょう。

その他のリソース