1. ホーム
  2. php

[解決済み] PHPのデータベースアクセスでシングルトンを使用するケースはありますか?

2022-05-25 11:29:04

質問

私は PDO を介して MySQL データベースにアクセスしています。データベースへのアクセスを設定しているのですが、最初に試したのは以下のようなものでした。

最初に思いついたのは global :

$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'root', 'pwd');

function some_function() {
    global $db;
    $db->query('...');
}

これは悪しき習慣とされています。少し検索したところ、結局は シングルトン・パターン というのを見つけました。

"は、クラスのインスタンスが1つである必要がある状況に適用されます。

マニュアルの例によると、こうすればいいようです。

class Database {
    private static $instance, $db;

    private function __construct(){}

    static function singleton() {
        if(!isset(self::$instance))
            self::$instance = new __CLASS__;

        return self:$instance;
    }

    function get() {
        if(!isset(self::$db))
            self::$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'user', 'pwd')

        return self::$db;
    }
}

function some_function() {
    $db = Database::singleton();
    $db->get()->query('...');
}

some_function();

こんなことができるのに、なぜあの比較的大きなクラスが必要なのでしょうか?

class Database {
    private static $db;

    private function __construct(){}

    static function get() {
        if(!isset(self::$db))
            self::$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'user', 'pwd');

        return self::$db;
    }
}

function some_function() {
    Database::get()->query('...');
}

some_function();

この最後のものは完璧に機能し、私は $db を気にする必要はありません。

どうすればより小さなシングルトンクラスを作ることができるでしょうか、あるいは私がPHPで見逃しているシングルトンのユースケースがあるのでしょうか?

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

さて、私がキャリアを始めたばかりの頃、このことについてしばらくの間悩みました。 さまざまな方法で実装し、静的クラスを使用しないことを選択する 2 つの理由を思いつきましたが、それはかなり大きなものでした。

1つは、絶対に2つ以上のインスタンスを持つことはないと思っていたものが、最終的には2つ目を持ってしまうことが非常によくあることです。 2つ目のモニター、2つ目のデータベース、2つ目のサーバーなど、あらゆるものがあります。

このようなことが起こると、静的クラスを使用していた場合は、シングルトンを使用していた場合よりもはるかに悪いリファクタリングが必要になります。 シングルトンはそれ自体あやふやなパターンですが、インテリジェントなファクトリー パターンにかなり簡単に変換でき、あまり問題なく依存性注入を使用するように変換することさえできます。 たとえば、シングルトンが getInstance() によって取得される場合、それを getInstance(databaseName) にかなり簡単に変更でき、複数のデータベースを使用できるようにすることができます。

2つ目の問題はテストです(そして正直なところ、これは最初の問題と同じです)。 時には、データベースをモックデータベースに置き換えたいと思うことがあります。 事実上、これはデータベースオブジェクトの2番目のインスタンスです。 静的なクラスでこれを行うのは、シングルトンの場合よりもはるかに困難です。静的なクラスのすべてのメソッドではなく、getInstance()メソッドをモックする必要があるだけです(これはいくつかの言語では非常に難しい場合があります)。

人々がグローバルは良くないと言うとき、彼らはそう言う非常に良い理由を持っていますが、それはあなた自身が問題にぶつかるまで常に明白ではないかもしれません。

あなたができる最善のことは、(あなたがしたように)尋ねてから、選択し、あなたの決定の影響を観察することです。 時間の経過に伴うコードの進化を解釈するための知識を持つことは、最初に正しく行うことよりもはるかに重要です。