web-dev-qa-db-ja.com

データベース接続用のグローバルまたはシングルトン?

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();
    .
    .
    .
}

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

78
Imran

これは古いことは知っていますが、Dr8kの答えはalmostでした。

コードの一部を書くことを検討しているときは、変更されると想定してください。それは、将来のある時点でそれが巻き上げられるような種類の変更を想定しているという意味ではなく、むしろ何らかの形の変更が行われるということです。

将来的に変更を行う際の苦痛を軽減することを目標にしてください。グローバルは単一の場所で管理するのが難しいため危険です。そのデータベース接続のコンテキストを将来的に認識させたい場合はどうすればよいですか?使用された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行のコード。これにより、何時間も何時間もリファクタリングを行ない、ひどく似たようなものにリファクタリングできます。

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

104
Jon Raphaelson

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

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

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

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

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

[編集]

大規模な状況では、dataseをヒットするたびに新しい接続を作成するのは悪いことです。ただし、答えはグローバル接続を作成し、それをすべてに再利用することではありません。答えは接続プーリングです。

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

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

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

16
Dr8k

シングルトンメソッドは、クラスのインスタンスが1つだけであることを確認するために作成されました。しかし、人々はグローバル化を短縮する方法としてそれを使用するので、それは怠zyなプログラミングや悪いプログラミングとして知られるようになります。

したがって、グローバルとシングルトンはどちらも実際にはOOPではないため、無視します。

あなたが探していたのは、依存性注入です。

http://components.symfony-project.org/dependency-injection/trunk/で、読みやすいPHP依存性注入に関連する情報(例付き)を確認できます。 book/01-Dependency-Injection

7
user1093284

どちらのパターンも同じ最終的な効果を達成し、データベース呼び出しに単一のアクセスポイントを提供します。

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

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

3
Adam Ness

永続的な接続を使用しない場合、およびそうしない場合がありますが、シングルトンはOO design。

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

2
Gavin M. Roy

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

2
Dprado

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

RWendi

1
RWendi

とても簡単です。グローバルOR Singleton。

0

アドバイスとしてsingletonglobalの両方が有効であり、同じシステム、プロジェクト、プラグイン、製品など内で結合できます...私の場合、Web用のデジタル製品(プラグイン)を作成しています。

メインクラスではsingletonのみを使用し、原則として使用します。メインクラスが再びインスタンス化しないことを知っているため、ほとんど使用しません。

<?php // file0.php

final class Main_Class
{
    private static $instance;
    private $time;

    private final function __construct()
    {
        $this->time = 0;
    }
    public final static function getInstance() : self
    {
        if (self::$instance instanceof self) {
            return self::$instance;
        }

        return self::$instance = new self();
    }
    public final function __clone()
    {
        throw new LogicException("Cloning timer is prohibited");
    }
    public final function __sleep()
    {
        throw new LogicException("Serializing timer is prohibited");
    }
    public final function __wakeup()
    {
        throw new LogicException("UnSerializing timer is prohibited");
    }
}

グローバルほとんどすべてのセカンダリクラスで使用、例:

<?php // file1.php
global $YUZO;
$YUZO = new YUZO; // YUZO is name class

一方、実行時にはGlobalを使用して同じインスタンスでメソッドと属性を呼び出すことができます。これは、メインの製品クラスの別のインスタンスが必要ないためです。

<?php // file2.php
global $YUZO;
$YUZO->method1()->run();
$YUZO->method2( 'parameter' )->html()->print();

私がグローバルで得ているのは、同じインスタンスを使用して製品を動作させることです。同じクラスのインスタンスのファクトリは必要ないためです。通常、インスタンスファクトリは大規模システム用または非常にまれな目的用です。

In conclusion:、アンチパターンSingletonであり、Globalであることが既に理解されている場合は、2つのオプションのいずれかを使用するか、それらを組み合わせて使用​​する必要がありますが、非常に例外的でプログラミングOOPに忠実なプログラマーが多いため、乱用しないことをお勧めします。実行時間内によく使用するメインクラスとセカンダリクラスに使用してください。 (多くのCPUを節約します)。 ????

0
Lenin Zapata