Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
对于数据库实现来说,这是一个好的PHP OOP结构吗?_Php_Database_Oop_Pdo_Abstract - Fatal编程技术网

对于数据库实现来说,这是一个好的PHP OOP结构吗?

对于数据库实现来说,这是一个好的PHP OOP结构吗?,php,database,oop,pdo,abstract,Php,Database,Oop,Pdo,Abstract,我有一系列的课程: abstract class Database extends PDO {} abstract class OracleDatabase extends Database {} abstract class MySQLDatabase extends Database {} abstract class MSSQLDatabase extends Database {} 然后,当我需要数据库连接的实例时,我会创建一个新类,该类扩展OracleDatabase、MySQLDa

我有一系列的课程:

abstract class Database extends PDO {}
abstract class OracleDatabase extends Database {}
abstract class MySQLDatabase extends Database {}
abstract class MSSQLDatabase extends Database {}
然后,当我需要数据库连接的实例时,我会创建一个新类,该类扩展
OracleDatabase
MySQLDatabase
MSSQLDatabase
,具体取决于数据库所在的位置。。。e、 g

class MyAppDatabase extends OracleDatabase {}
首先,这是一个好的设计吗?我已经读到使用接口比扩展抽象类更好,但我不知道如何在不重复代码的情况下做到这一点

我确实意识到PDO的全部目的是摆脱特定于DB的代码,但对于DB对象括号(例如,在Oracle中,使用双引号;在MySQL中,使用反勾号)、数据类型检测(用户选项卡列与信息模式)等,我仍然需要不同的功能

并且-如果我想创建一个名为
Updater
的类,该类允许客户端创建一组对特定表的多个“更新”——使用set和WHERE子句的相同字段,但使用不同的值,该怎么办?我不认为我能够从
数据库
类继承,所以我会让它成为一个“拥有”数据库对象的独立类吗

class Updater {

    private $db;

    private $table;

    private $setFields;

    private $whereFields;

    private $updates;

    function __construct($db, $table, $setFields, $whereFields) {
        if (!($db instanceof Database)) {
            if (is_scalar($db)) {
                $type = gettype($db);
            } else {
                $type = get_class($db);
            }
            throw new Exception("Expected Database object; " . $type . " found.");
        }

        $this->db = $db;

        // ensure $table is a table in the database
        // ensure $setFields and $whereFields are columns in the table

        $this->table = $table;
        $this->setFields = $setFields;
        $this->whereFields = $whereFields;
        $this->updates = array();
    }


    function addUpdate($setValues, $whereValues)  {

        // ensure $setValues is an array and has the same cardinality as
        //     $this->setFields

        // ensure $whereValues is an array and has the same cardinality as
        //     $this->whereFields

        array_push($this->updates,
            array(
                'setValues'=>$setValues,
                'whereValues' => $whereValues
            )
        );
    }

    function doUpdate() {   // without error handling

        $escTable = $this->db->bracket($table);

        $setTemplate = array();

        foreach ($this->setFields as $setField) {
            $escField = $this->db->bracket($setField);
            $colonField = makeColonField($setField);   // :fieldName
            $setting = "$escField = $colonField";
            array_push($setTemplate, $setting);
        }

        $csvSetTemplate = implode(", ", $setTemplate);

        $whereTemplate = array();

        foreach ($this->whereFields as $whereField) {
            $escField = $this->db->bracket($whereField);
            $colonField = makeColonField($setField);   // :fieldName
            $setting = "$escField = $colonField";
            array_push($whereTemplate, $setting);
        }

        $andedWhereTemplates = implode(" AND ", $whereTemplate);

        $sql = "UPDATE $escTable SET $csvSetTemplate WHERE $andedWhereTemplates";

        $sth = $this->db->prepare($sql);

        foreach ($this->updates as $update) {

            $setValues   = $update['setValues'];
            $whereValues = $update['whereValues'];

            $params = array();
            for ($i=0; $i<count($setValues); $i++) {
                $setField = $this->setFields[$i];
                $setValue = $setValues[$i];
                $colonField = makeColonField($setField);
                $params[$colonField] = $setValue;
            }

            for ($i=0; $i<count($whereValues); $i++) {
                $whereField = $this->whereFields[$i];
                $whereValue = $whereValues[$i];
                $colonField = makeColonField($whereField);
                $params[$colonField] = $whereValue;
            }

            $sth->execute($params);
        }
    }
}
类更新程序{
私人$db;
私人$table;
私有$setFields;
私人领域;
私人$更新;
函数u_构造($db、$table、$setFields、$whereFields){
if(!($db instanceof Database)){
if(是_标量($db)){
$type=gettype($db);
}否则{
$type=get_类($db);
}
抛出新异常(“预期的数据库对象;”$type。“已找到”);
}
$this->db=$db;
//确保$table是数据库中的表
//确保$setFields和$whereFields是表中的列
$this->table=$table;
$this->setFields=$setFields;
$this->whereFields=$whereFields;
$this->updates=array();
}
函数addUpdate($setValues,$whereValues){
//确保$setValues是一个数组,并具有与相同的基数
//$this->setFields
//确保$whereValues是一个数组,并具有与相同的基数
//$this->whereFields
阵列推送($this->更新,
排列(
“setValues”=>$setValues,
'whereValues'=>$whereValues
)
);
}
函数doUpdate(){//无错误处理
$escTable=$this->db->方括号($table);
$setTemplate=array();
foreach($this->setFields作为$setField){
$escField=$this->db->方括号($setField);
$colonField=makeColonField($setField);//:fieldName
$setting=“$ESCFELD=$COLONFELD”;
数组推送($setTemplate,$setting);
}
$csvSetTemplate=内爆(“,”,$setTemplate);
$whereTemplate=array();
foreach($this->whereFields作为$whereField){
$escField=$this->db->方括号($whereField);
$colonField=makeColonField($setField);//:fieldName
$setting=“$ESCFELD=$COLONFELD”;
数组_push($whereTemplate,$setting);
}
$andewheretemplates=内爆(“AND”,$whereTemplate);
$sql=“更新$escTable SET$CSVSETEMPLATE WHERE$andedWhereTemplates”;
$sth=$this->db->prepare($sql);
foreach($this->更新为$update){
$setValues=$update['setValues'];
$whereValues=$update['whereValues'];
$params=array();
对于($i=0;$isetFields[$i];
$setValue=$setValues[$i];
$colonField=makeColonField($setField);
$params[$colonField]=$setValue;
}
对于($i=0;$i此处字段[$i];
$whereValue=$whereValues[$i];
$colonField=makeColonField($whereField);
$params[$colonField]=$whereValue;
}
$sth->execute($params);
}
}
}

这是一个好的解决方案吗?

首先,我建议在这种情况下,抽象类更好,因为不同的RDBMS之间通常有许多共同点,您可以编写一些通用方法来更清楚地解决问题

还有另一种方法可以做到这一点:

class Database extends PDO {
    private $engine; //this is a DBEngine
}

interface DBEngine  
{
}

class MySQLEngine implements DBEngine
{

}

class MSSQLEngine implements DBEngine
{

}

...
在这种情况下,您可以使用接口,因为常用方法是在数据库中实现的,而每个引擎只实现在RDBMS之间具有不同行为的方法

这称为适配器模式,您可以在CodeIgniter的源代码中阅读一些关于此模式的内容:

对于第二个问题,您可以在类数据库中实现update方法


换句话说,让“更新”成为类数据库的公共成员。

我更倾向于使用数据库包装类,然后注入“提供者”(提供者是MySQL、Oracle或其他一些数据库引擎),然后通过包装类与数据库交互

您将有一个引导文件来设置这些,然后将新创建的数据库对象实例传递给应用程序

这称为依赖注入。理论上,您可以轻松地将数据库引擎切换到另一个,甚至可以注入测试数据库并使用相同的应用程序

一个快速、即时的例子:

<?php
class Database
{    
    private $database;

    public function setProvider(DatabaseProvider $database)
    {
        $this->database = $database;
    }

    public function select($table, $fields = array(), $conditions = array(), $order = array())
    {
        $this->database->select($table, $fields, $conditions, $order);
    }

    public function insert($table, $values)
    {
        $this->database->insert($table, $values);
    }

    public function delete($table, $conditions = array())
    {
        $this->database->delete($table, $conditions);
    }
}

您真的需要同时使用所有这些实例吗?是否需要将
Oracle/MySQL/MSSQLSDATABASE
声明为抽象的?似乎它们可以是具体的,而不是声明一个新类来声明每个实例。@您的常识,不确定。我希望能够在不影响应用程序的情况下灵活地切换DB实现n代码。@Pudge601,我想它们可能是具体的。PDO不是已经提供了这种抽象级别吗?只是查看了codeigniter。看起来很棒。我可能会在我的下一个项目中使用它。:)
<?php
class MySQL implements DatabaseProvider
{
    public function __construct($config)
    {
        // create PDO instance with settings in $config
        $this->connection = new PDO();
    }

    public function select($table, $fields = array(), $conditions = array(), $order = array())
    {
        // build SELECT statement based on table, and other parameters passed
        // return result set
    }

    // and so on...
}
/app
    /config
        database.xml
/src
    /VendorName
        /AppName
            /Database
                /Provider
                    DatabaseInterface.php
                    MSSQL.php
                    MySQL.php
                    Oracle.php
            Database.php
        Application.php
        Bootstrap.php