これを解決する正しい方法は、データベース オブジェクトを他のクラスに注入することです (依存性注入)。
$db = new DB_MySQL("localhost", "root", "", "test"); // connect to the database
include_once("pagi.php");
$pagination = new Paginator($db);
$records = $pagination->get_records("SELECT the, fields, you, want, to retrieve FROM `table`");
class Paginator
{
protected $db;
// Might be better to use some generic db interface as typehint when available
public function __construct(DB_MySQL $db)
{
$this->db = $db;
}
public function get_records($q) {
$x = $this->db->query($q);
return $this->db->fetch($x);
}
}
それを解決する別の方法は、データベース クラスのインスタンスを、それを使用するメソッドに挿入することです。
$db = new DB_MySQL("localhost", "root", "", "test"); // connect to the database
include_once("pagi.php");
$pagination = new Paginator();
$records = $pagination->get_records("SELECT the, fields, you, want, to retrieve FROM `table`", $db);
class Paginator
{
public function get_records($q, DB_MySQL $db) {
$x = $db->query($q);
return $db->fetch($x);
}
}
どちらの方法を選択するかは、状況によって異なります。1 つのメソッドだけがデータベースのインスタンスを必要とする場合は、それをメソッドに挿入できます。それ以外の場合は、クラスのコンストラクターに挿入します。
pagi
また、クラスの名前を からに変更したことにも注意してくださいPaginator
。Paginator は、他の人がコードを (再) 表示することが明確であるため、クラスの名前としては私見の方が適切です。また、最初の文字を大文字にしたことに注意してください。
私が行ったもう1つのことは、「ワイルドカード」を使用する代わりに、使用しているフィールドを選択するようにクエリを変更することです*
。これは、クラス名を変更したのと同じ理由です。コードを (再) 表示する人は、データベースや結果を確認しなくても、どのフィールドが取得されるかを正確に知ることができます。
アップデート
回答により、 object を宣言する代わりに依存性注入ルートを使用する理由についての議論が生じたためglobal
、キーワードで依存性注入を使用する理由を明確にしたいと思いglobal
ます。次のようなメソッドがある場合:
function get_records($q) {
global $db;
$x = $db->query($q);
return $db->fetch($x);
}
上記のメソッドをどこかで使用している場合、使用するクラスまたはメソッドが に依存していることは明確ではありません$db
。したがって、これは隠れた依存関係です。上記が悪いもう1つの理由は、$db
インスタンス(したがってDB_MySQL
)クラスをそのメソッド/クラスに密結合しているためです。ある時点で 2 つのデータベースを使用する必要がある場合はどうでしょうか。global $db
に変更するには、すべてのコードを実行する必要がありますglobal $db2
。別のデータベースに切り替えるためだけにコードを変更する必要はありません。このため、次のことを行うべきではありません。
function get_records($q) {
$db = new DB_MySQL("localhost", "root", "", "test");
$x = $db->query($q);
return $db->fetch($x);
}
DB_MySQL
繰り返しますが、これは隠れた依存関係であり、クラスをメソッド/クラスに緊密に結合します。Paginator
このため、クラスを適切に単体テストすることもできません。ユニット (クラス) だけをテストする代わりに、同時にクラスPaginator
もテストしています。DB_MySQL
また、複数の密接に結合された依存関係がある場合はどうなるでしょうか? ここで、いわゆる単体テストで突然いくつかのクラスをテストしています。したがって、依存性注入を使用すると、別のデータベース クラスに簡単に切り替えることができます。また、テスト目的でモック化されたクラスに切り替えることもできます。1 つのユニットのみをテストする利点 (依存関係のために間違った結果が得られることを心配する必要はありません) に加えて、テストが迅速に終了することも保証されます。
シングルトン パターンがデータベース オブジェクトへのアクセスを取得する正しい方法だと考える人もいるかもしれませんが、上記のすべてを読んで、シングルトンは基本的に物事を作成する別の方法であることは明らかglobal
です。見た目は違うかもしれませんが、 とまったく同じ特性を持っているため、 と同じ問題がありglobal
ます。