【问题标题】:OO PHP - How to create a "generic" database object?OO PHP - 如何创建“通用”数据库对象?
【发布时间】:2011-07-27 10:40:38
【问题描述】:

继续我进入更高级 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 编辑器中是相当微不足道的,但它仍然不应该是最好的方法(我现在开始学习理论而不是实践!)

所以最后,我希望我可以使用单个 switch 语句构建 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-&gt;query,因为该方法在数据库对象中不存在。

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

总结 - 我几乎可以肯定我错过了一些东西,我想做的事情应该既可能又非常简单,我只是没有想到正确的方法 - 任何人都可以给我指点吗?

【问题讨论】:

  • +1 表示出于“必须有更好的方法”提出的好问题。我会考虑一个工厂,它返回一个代理对象,然后委托给隐藏在里面的真实对象,但话说回来,我不是 PHP 程序员。
  • 还要注意不同的数据库倾向于支持不同的SQL方言;这会使它们之间的切换比您预期的更难。
  • @Donal 这正是我以我现在的方式看待它的原因,所以后来的方法比如说 - selectAllRecords($table,$order) - 将能够以特定数据库的方式编写 SQL需要它来写。虽然我担心可能无法找到一种方法来消除在类之外编写任何 SQL 的需要(当涉及到复杂的查询时),但我绝对可以摆脱简单的东西。
  • 我或许还应该指出,尽管我的示例很简单,但我喜欢添加许多其他功能(例如查询分析),因此这不仅仅是重新发明轮子的情况。

标签: php oop object


【解决方案1】:

尽管事实上您正在做的是重新发明轮子(看看 PDO),但一般来说,对于这样的情况,您可能想要使用类似 factory pattern 的东西。

在基本伪代码中:

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

【讨论】:

  • 我认为这会赢!就像我在问题的最后一个代码块中所做的那样,只有我在构造函数中有return new xxxx,这不起作用。将它们移到 create 方法中很有效!
【解决方案2】:

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

【讨论】:

  • 我个人讨厌没有需要的用户创建的库。重写轮子。
  • 我会调查一下,但可能出现的一个问题是我没有托管我编写的所有内容,因此我并不总是可以访问 PHP 配置(有时我没有'甚至无法访问 PHP5!)
  • PHP 4 不再受支持,如果您有客户仍在使用它,那么我倾向于敦促他们升级。如果不出意外的话,为了保护自己,PHP 4 包含永远无法修复的漏洞,使用它基本上会使正在运行的服务器容易受到攻击。
【解决方案3】:

在这种情况下,我一般会:

  • 定义一些DAOInterface,使用connectqueryfecthAll等方法
    • 连接到数据库的所有类都必须实现该接口
    • 这意味着您的mysql_daomysqli_dao、...将实现该接口

然后,在使用这些类时,主要优点是:

  • 稍后您将实例化为$db 变量,mysql_daomysqli_dao,但始终获得实现DAOInterface 的对象
  • 这意味着您将确定可以在您的 $db 对象上调用所有这些方法


之后,您将只需要在 mysql_daomysqli_dao 之间进行选择:当您实例化这两者之一时,将结果分配给 $db

那么,正如您确定$db 是一个实现DAOInterface 的对象一样,您肯定知道您将始终能够在该对象上调用相同的方法。

【讨论】:

  • 这是我想出的解决方案之一(我只是没有谈论原始问题中的接口)但这仍然意味着我必须直接调用 DAO,所以如果我想更改,每个使用数据库的页面中的调用代码都会发生更改(不考虑使用包含等)。
  • 在任何地方都不会有任何变化(除非您将 DAO 实例化并将其分配给 $db),只要您的所有 DAO 实现相同的接口:代码使用该接口的方法将保持完全相同。
  • 我明白 - 我只是想变得更懒惰 :-) 实例化代码始终为 new database,无论它使用哪个实际 DAO。
【解决方案4】:

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

 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 数据库接口,但我相信你会找到一种方法来为不同类型的 DB 创建一个对象。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-29
    • 2018-12-30
    • 2013-11-22
    • 1970-01-01
    • 1970-01-01
    • 2010-12-21
    • 1970-01-01
    相关资源
    最近更新 更多