簡體   English   中英

這是用於數據庫實現的良好PHP OOP結構嗎?

[英]Is this a good PHP OOP structure for a Database Implementation?

我有一系列的課程:

abstract class Database extends PDO {}
abstract class OracleDatabase extends Database {}
abstract class MySQLDatabase extends Database {}
abstract class MSSQLDatabase extends Database {}

然后,當我想要數據庫連接的實例時,我將創建一個新類, MSSQLDatabase根據數據庫所在的位置擴展了OracleDatabaseMySQLDatabaseMSSQLDatabase

class MyAppDatabase extends OracleDatabase {}

首先,這是一個好的設計嗎? 我已經讀到使用接口比擴展抽象類更好,但是我不確定如何在不復制代碼的情況下做到這一點。

我確實意識到PDO的全部目的是擺脫特定於DB的代碼,但是當針對DB對象括弧(例如,在Oracle中,您使用雙引號;在MySQL中您使用反引號),數據時,我仍然需要其他功能類型檢測(user_tab_columns與INFORMATION_SCHEMA),等等。

並且-如果我想創建一個名為Updater的類,該類使客戶端可以對特定表創建一組多個“更新”,-使用SET和WHERE子句的相同字段,但使用不同的值呢? 我認為我無法從Database類繼承,因此我是否可以將其設為“ HAS”數據庫對象的獨立類?

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);
        }
    }
}

這是一個好的解決方案嗎?

首先,我建議在這種情況下使用抽象類更好,因為不同的RDBMS之間通常存在許多共同點,您可以使用它們編寫一些通用方法來更清楚地解決問題。

還有另一種方法:

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

interface DBEngine  
{
}

class MySQLEngine implements DBEngine
{

}

class MSSQLEngine implements DBEngine
{

}

...

在這種情況下,可以使用接口,因為通用方法是在數據庫中實現的,並且每個引擎僅實現在RDBMS之間行為不同的方法。

這稱為適配器模式,您可以在CodeIgniter的源代碼中找到一些相關信息: http : //ellislab.com/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);
    }
}

然后是一個提供者示例:

<?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...
}

將在引導文件中創建MySQL實例,並在其中傳遞連接設置。

顯然,以上並不是一個完整的示例,但足以使您開始充實自己的解決方案。

獎金

示例目錄結構受Symfony 2的啟發。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM