OO PHP -如何创建一个“泛型”数据库对象


OO PHP - How to create a "generic" database object?

继续我的更高级的OO之旅,我试图想出一个最好的方法来创建一个叫做database的类,它可以愉快地使用即将被弃用的mysql_命令,mysqli_库,也许进一步下去,其他风格的数据库也可以。

为了简单,我希望我的调用代码看起来像这样:

$db = new database("MYSQL", $host,$user,$password,$databaseName); 
$db->query("SELECT myField FROM myTable");
while ($ROW = $db->fetch_assoc($QRY)) {
  echo $ROW['myField'] . "<br/>";
}

当实例化数据库对象时,这是我希望指定MYSQL, MYSQLI, MSSQL或任何我想稍后添加的部分。

我很感激我可以通过在database的每个方法中实现switch块来实现我想要的:

class database() {
  function __construct($type,$host,$user,$password,$databaseName) { 
    $this->dbType = $type; 
    switch ($type) {
      case "mysql":
        mysql_dao::connect($host,$user,$password,$databaseName);
        break;
      case "mysqli":
        mysqli_dao::connect($host,$user,$password,$databaseName);
        break;
      case "mssql":
        mssql_dao::connect($host,$user,$password,$databaseName);
        break;
      //other cases
    }
  }
  function query($SQL) {  
    switch ($this->dbType) { 
       case "mysql": mysql_dao::query($SQL); break;
       case "mysqli": mysqli_dao::query($SQL); break; 
       case "mssql": mssql_dao::query($SQL); break;
    }
  }
  function fetch_assoc($SQL) {  
    switch ($this->dbType) { 
       case "mysql": mysql_dao::fetch_assoc($SQL); break;
       case "mysqli": mysqli_dao::fetch_assoc($SQL); break; 
       case "mssql": mssql_dao::fetch_assoc($SQL); break;
    }
  }
  //other methods....
}

…但这看起来非常混乱。每次调用database的方法时,代码都会检查它是什么类型,并从不同的对象调用该方法。

所以我的下一个解决方案是简单地忽略database,只是使用调用代码,看起来像这样:

$db = new mysql_dao($host,$user,$password,$databaseName); 
$db->query("SELECT myField FROM myTable");
while ($ROW = $db->fetch_assoc($QRY)) {
  echo $ROW['myField'] . "<br/>";
}

…根据数据库类型调用数据库访问对象,但我也不喜欢这样,如果我想把整个项目从mysql转移到mysqli,我就得找出所有这些对象引用并修改它们。虽然这在现代PHP编辑器中是相当微不足道的,但它仍然感觉不应该是最好的方法(现在我开始从实际出发,而不是从理论出发!)

所以最后,我希望我可以用一个开关语句构建database类:

class database {
    function __construct($type,$host,$user,$pass,$db) {    
        switch ($type) {
            default:
            case "MYSQL":
                return new mysql_dao($host,$user,$pass,$db);
                break;
            case "MYSQLI":
                return new mysqli_dao($host,$user,$pass,$db);
                break;
            case "MSSQL":
                return new mssql_dao($host,$user,$pass,$db);
                break;    
        }    
    }
}

…然后实现一个接口所有其他的方法都在类中用于各个数据库类型。不幸的是,这也不起作用,因为即使database的构造函数返回另一个对象的实例,我也不能调用database->query,因为该方法不存在于数据库对象中。

据我所知,用mysql_dao/mysqli_dao等类扩展database也是不对的,因为你必须调用扩展类来使用它的方法,我想调用父类,但使用子类的方法。所以这表明database应该扩展dao类,但你不能有一个子类与多个潜在的父母(你可以吗?)

总结-我几乎肯定我错过了一些东西,我想做的应该是既可能又相当直接的,我只是没有想到正确的方法-谁能给我一个指针?

尽管您正在做的是重新发明轮子(看看PDO),但通常情况下,对于这种情况,您可能希望使用类似工厂模式的东西。

在基本伪代码中:

$db = Database::create('mysql', $host, ...); // gets a MySQLDatabase object
$db = Database::create('mysqli', $host, ...); // gets a MySQLiDatabase object

为什么不直接使用PDO?它提供了与一系列数据库连接的统一方式(它执行的实际查询必须考虑到目标数据库,但无论连接到哪种数据库,API都是相同的)。

在这种情况下,我会:

  • 定义一些DAOInterface,方法如connect, query, fecthAll,…
    • 所有连接到数据库的类都必须实现该接口
    • 这意味着你的mysql_dao, mysqli_dao,…将实现该接口

那么,当使用这些类时,主要的优点是:

  • 您稍后将实例化,作为$db变量,mysql_daomysqli_dao,但总是得到一个实现DAOInterface的对象
  • 这意味着你将确保你可以调用所有这些方法,在你的$db对象


在那之后,只有一个地方你必须在mysql_daomysqli_dao之间进行选择:当你实例化这两个中的一个时,将结果赋值给$db

那么,既然你知道$db是一个实现DAOInterface的对象,你就知道你总是能够在那个对象上调用相同的方法。

为了使功能发挥作用,您需要传递和返回参数作为引用,如下面的示例所示:

 public function &Query($sql){
     $var = mysql_query($sql, $this->connection);
     return $var;
 }
 public function Fetch(&$cur){
     return mysql_fetch_array($cur);
 }

"&"表示变量的引用,而不仅仅是更多文档的副本:http://www.php.net/manual/en/language.references.pass.php

你正在努力做的事情很有效。我创建了一个MySQL数据库接口,但我相信您会找到一种方法来为不同类型的数据库创建对象。