我正在尝试创建一个基本框架的骨架,但我偶然发现了一种情况,我发现自己缺少一些引擎。
我有这个类来管理MySQL连接:
class Mysql implements IConnection {
protected $user;
protected $pass;
protected $dbhost;
protected $dbname;
protected $dbh;
public function __construct($user, $pass, $dbhost, $dbname)
{
$this->user = $user;
$this->pass = $pass;
$this->dbhost = $dbhost;
$this->dbname = $dbname;
}
public function connect()
{
// implementation
}
public function prepare($query)
{
// implementation
}
}
现在我想使用工厂+单例来管理这个类的唯一实例:
class Database
{
private static $db;
private function __construct() {}
public function getInstance($DBType = 'mysql')
{
if (! isset(self::$db)) {
switch ($DBType) {
case 'mysql':
self::$db = new Mysql(); // <---- PROBLEM HERE!!
// more database types should follow
}
}
return self::$db;
}
}
注意这样我每次需要数据库连接实例时都应该传递工厂方法的连接参数,这肯定不方便。
唯一想到的是将先前创建的数据库连接传递给Mysql :: __ construct()并将其存储在属性中,以便在Mysql :: prepare()中使用,但它会打破界面:Mysql :: connect()没有任何意义,我不能将这个类的db连接与查询管理一起包装。
你建议我做什么?
修改 这是我自己的尝试,虽然我需要更改界面,但我不确定它是否是一个好方法: - 更改接口,以便IConnection :: connect()接受连接参数而不是构造函数
class Mysql implements IConnection {
protected $dbh; // now I only need this property
public function __construct()
{
}
public function connect($user, $pass, $dbhost, $dbname)
{
// implementation
}
public function prepare($query)
{
// implementation
}
}
和Singleton工厂:
class Database
{
private static $db;
private function __construct() {}
public function getInstance($DBType = 'mysql')
{
if (! isset(self::$db)) {
switch ($DBType) {
case 'mysql':
self::$db = new Mysql;
break;
case 'mssql':
self::$db = new Mssql;
break;
case 'postgresql':
self::$db = new Postgresql;
break;
// etc
}
}
return self::$db;
}
}
我认为这种方式足够干净。一些客户端代码:
$db = Database::getInstance(Config::get('db_driver'));
$db->connect(Config::get('db_user'),
Config::get('db_pass'),
Config::get('db_host'),
Config::get('db_name'));
欢迎提出建议和更正。