どもです。
今回は最近の悩みについて。
プロジェクトを1から立ち上げるとき、共用のクラスをどうするかが問題になる。
だいたいはstatic関数にしてしまうか都度newするかで解決するのだけど、データベースを扱うクラスだけは簡単にいかない。
●前提
・このプロジェクトで使用するデータベースは1つのみであり、データベース情報は定数で宣言する。
・DBクラスはプログラムの開始時に一度だけ宣言し、全てのクラスで同じインスタンスを使いまわす。
・DB操作はmysqli関数を使用する。(PDOでも同じことになるはずだが)
class DB{
protected $mysql = null;
function __construct(){
$this->mysql = null;
if($this->mysql = mysqli_connect(host, user, pass)) {
if(!mysqli_select_db($this->mysql, name)){
throw new \Exception("データベースへの接続に失敗しました。");
}
}
}
function query($sql){
return mysqli_query($this->mysql, $sql);
}
}
①グローバル変数にする
$db = new DB();
class test{
function a($sql){
$GLOBALS['db']->query($sql);
}
}
ggった場合に出てくる解決法はだいたいグローバル化だが、クラスの中で使用するとこうなるのでスマートとは言い難い。
あとグローバル変数は使うな勢力が幅を利かせている昨今、このやり方は文句を言われそうだ。
②エントリーポイントで取得したインスタンスを処理クラスに渡す
class Main{
function __construct(){
$db = new DB();
$test = new test($db);
$test->a($sql);
}
}
class test{
function __construct($db){
$this->db = $db;
}
function a($sql){
$this->db->query($sql);
}
}
次に思いつくのは、共通処理の最初に宣言したインスタンスを処理クラスのコンストラクトに手渡しする手段。
しかし、こちらもスマートと言えたものではない。明示的に手渡ししたクラスでしかDBが使えないから拡張性に欠けるし、コンストラクタがぐちゃぐちゃするのは個人的に嫌いだ。
③DBクラスをシングルトンにする
class DB{
protected $mysql = null;
protected static $instance = null;
private function __construct(){
略
}
function query($sql){
return mysqli_query($this->mysql, $sql);
}
static function getInstance(){
if (isset(self::$instance)) {
return self::$instance;
}
self::$instance = new DB;
return self::$instance;
}
}
class test(){
function a($sql){
$db = DB::getInstance();
$db->query($sql);
}
}
辿り着いたのがコレ。シングルトンという概念を知らなかったので目から鱗だった。
なるほど、DBクラスが自身の単一のインスタンスをstaticに持ってしまえば、staticで同じ接続を取り出すことができるわけだ。実にスマートだ。