81

PHPでデータベース接続にグローバルではなくシングルトンを使用する利点は何ですか? グローバルの代わりにシングルトンを使用すると、コードが不必要に複雑になると思います。

グローバルなコード

$conn = new PDO(...);

function getSomething()
{
    global $conn;
    .
    .
    .
}

シングルトンを使用したコード

class DB_Instance
{
    private static $db;

    public static function getDBO()
    {
        if (!self::$db)
            self::$db = new PDO(...);

        return self::$db;
    }
}

function getSomething()
{
    $conn = DB_Instance::getDBO();
    .
    .
    .
}

グローバルまたはシングルトン以外のデータベース接続を初期化するより良い方法がある場合は、それについて言及し、グローバルまたはシングルトンよりも優れていることを説明してください。

4

9 に答える 9

105

私はこれが古いことを知っていますが、Dr8kの答えはほとんどそこにありました.

コードを書くことを検討しているときは、それが変更されると想定してください。これは、将来のある時点でどのような変化がもたらされるかを想定しているという意味ではなく、何らかの形の変化が行われるという意味です。

それを目標にして、将来の変更の痛みを軽減します。グローバルは、1 つの場所で管理するのが難しいため危険です。将来、そのデータベース接続コンテキストを認識させたい場合はどうすればよいですか? 5回使用するたびに閉じてから再度開くようにしたい場合はどうすればよいですか。アプリをスケーリングするために、10 個の接続のプールを使用することにした場合はどうなりますか? または、構成可能な接続数ですか?

シングルトン ファクトリはその柔軟性を提供します。余分な複雑さをほとんど加えずにセットアップし、同じ接続にアクセスするだけではありません。その接続が後で簡単な方法で自分に渡される方法を変更することができます。

単にsingletonではなく、 singleton factoryと言うことに注意してください。シングルトンとグローバルの間にはほとんど違いがありません。そのため、シングルトン接続を使用する理由はありません。代わりに通常のグローバルを作成できるのに、なぜそれを設定するのに時間を費やすのでしょうか?

ファクトリが取得するのは、接続を取得する理由と、取得する接続 (または接続) を決定する別の場所です。

class ConnectionFactory
{
    private static $factory;
    private $db;

    public static function getFactory()
    {
        if (!self::$factory)
            self::$factory = new ConnectionFactory(...);
        return self::$factory;
    }

    public function getConnection() {
        if (!$this->db)
            $this->db = new PDO(...);
        return $this->db;
    }
}

function getSomething()
{
    $conn = ConnectionFactory::getFactory()->getConnection();
    .
    .
    .
}

それから 6 か月後に、あなたのアプリが非常に有名になり、スラッシュドットが掘り下げられ、複数の接続が必要であると判断した場合、getConnection() メソッドにいくつかのプーリングを実装するだけで済みます。または、SQL ロギングを実装するラッパーが必要であると判断した場合は、PDO サブクラスを渡すことができます。または、呼び出しごとに新しい接続が必要であると判断した場合は、それを行うことができます。硬いのではなく、柔軟です。

中かっこを含む 16 行のコード。これにより、何時間も何時間もリファクタリングして、不気味なほど似たものにリファクタリングする必要がなくなります。

最初のラウンドでは機能の実装を行っていないため、この「機能のクリープ」を考慮していないことに注意してください。「Future Creep」の境界線ですが、ある時点で、「明日のために今日コーディングする」という考えは常に悪いことではありません。

于 2008-10-20T19:37:20.160 に答える
16

あなたの特定の質問に答えられるかどうかはわかりませんが、これが Web ベースのシステムの場合、グローバル/シングルトン接続オブジェクトは最良のアイデアではない可能性があることを示唆したいと思います。DBMS は一般に、多数の一意の接続を効率的に管理するように設計されています。グローバル接続オブジェクトを使用している場合は、いくつかのことを行っています。

  1. ページにすべてのデータベース接続を順番に実行させ、非同期のページ読み込みの試みを強制終了します。

  2. データベース要素の開いたロックを必要以上に長く保持し、データベース全体のパフォーマンスを低下させる可能性があります。

  3. データベースがサポートできる同時接続の合計数を最大にし、新しいユーザーがリソースにアクセスできないようにします。

他の潜在的な結果もあると確信しています。このメソッドは、サイトにアクセスするすべてのユーザーのデータベース接続を維持しようとすることに注意してください。ユーザーが 1 人か 2 人しかいない場合は問題ありません。これが公開 Web サイトで、トラフィックが必要な場合は、スケーラビリティが問題になります。

[編集]

大規模な状況では、データベースにアクセスするたびに新しい接続を作成するのは良くない場合があります。ただし、答えは、グローバル接続を作成してすべてに再利用することではありません。答えは接続プーリングです。

接続プーリングを使用すると、多数の個別の接続が維持されます。アプリケーションで接続が必要になると、プールから最初に使用可能な接続が取得され、ジョブが完了するとプールに返されます。接続が要求されたが利用できない場合、次の 2 つのいずれかが発生します。a) 許可された接続の最大数に達していない場合、新しい接続が開かれるか、b) アプリケーションは接続が利用可能になるまで待機することを余儀なくされます。 .

注: .Net 言語では、接続プーリングはデフォルトで ADO.Net オブジェクトによって処理されます (接続文字列によってすべての必要な情報が設定されます)。

これについてコメントしてくれた Crad に感謝します。

于 2008-09-25T01:05:47.047 に答える
3

どちらのパターンでも、データベース呼び出しに 1 つのアクセス ポイントを提供することで、実質的に同じ効果が得られます。

特定の実装に関しては、シングルトンには、他のメソッドの少なくとも 1 つが要求するまでデータベース接続を開始しないという小さな利点があります。実際には、私が書いたほとんどのアプリケーションで、これは大きな違いはありませんが、データベース呼び出しをまったく行わないページ/実行パスがある場合、潜在的な利点になります。データベースへの接続を要求することはありません。

もう 1 つの小さな違いは、グローバルな実装が意図せずにアプリケーション内の他の変数名を踏みにじる可能性があることです。別のグローバルな $db 参照を誤って宣言することはまずありませんが、誤って上書きする可能性はあります (たとえば、if($db == null) と書くつもりだったときに if($db = null) と書く可能性があります)。シングルトンオブジェクトはそれを防ぎます。

于 2008-09-25T02:44:19.760 に答える
2

永続的な接続を使用する予定がなく、そうしない場合がある場合、OO 設計ではシングルトンがグローバルよりも概念的に受け入れやすいことがわかります。

真の OO アーキテクチャでは、オブジェクトの新しいインスタンスを毎回作成するよりもシングルトンの方が効果的です。

于 2008-09-25T01:03:55.867 に答える
2

与えられた例では、シングルトンを使用する理由はありません。経験則として、オブジェクトの単一のインスタンスを許可することだけを考えている場合、言語で許可されている場合は、グローバルを使用することを好みます

于 2008-09-25T01:06:13.053 に答える
1

一般に、データベース接続にはシングルトンを使用します...データベースとやり取りする必要があるたびに新しい接続を作成したくない...これにより、ネットワークのパフォーマンスと帯域幅が損なわれる可能性があります...新しいもの、利用可能なものがある場合...ちょうど私の2セント...

Rウェンディ

于 2008-09-25T01:14:39.803 に答える
0

それは非常に簡単です。グローバル OR シングルトンは使用しないでください。

于 2008-09-25T00:59:56.470 に答える