2011-07-27 43 views
1

繼續我的旅程進入更高級的面向對象,我試圖想出能夠創建一個名爲database的類的最佳方式,該類可以愉快地使用即將被棄用的mysql_命令,mysqli_庫和也許還有其他風格的數據庫。OO PHP - 如何創建「通用」數據庫對象?

我想我的調用代碼看起來像這樣,爲了簡單:

$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->query,因爲該方法在數據庫對象中不存在。

至於我可以工作了,與mysql_dao/mysqli_dao等類擴展database是不正確的決定,因爲你必須調用擴展的類來使用它的方法,我想調用父類的,但使用子類的方法。因此,這意味着database應該擴展dao類,但你不能有多個潛在的父母一個子類

在結束(可能嗎?) - 我幾乎可以肯定,我失去了一些東西,而我想要的要做的事情應該既可能也很直接,我只是沒有想到正確的方式 - 任何人都可以給我一個指針?

+0

+1對於一個被「必須有更好的方式」驅動的好問題+1。我會考慮一個返回一個代理對象的工廠,然後委託給隱藏在其中的實際對象,但是我又不是PHP程序員。 –

+0

另外請注意,不同的數據庫傾向於支持不同的SQL方言;這可以使它們之間的切換比你期望的更難。 –

+0

@Donal這正是我以這種方式看待它的原因,所以後來的方法如say - selectAllRecords($ table,$ order) - 將能夠以特定數據庫需要寫入的方式編寫SQL。儘管我擔心找到一種方法可以避免在類之外編寫任何SQL(當涉及到複雜的查詢時),但我絕對可以擺脫簡單的東西。 – Codecraft

回答

4

儘管你正在做的是重新發明輪子(看看PDO),但總的來說,對於這樣的情況,你可能想要使用類似factory pattern的東西。

在基本僞代碼:

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

我覺得這個勝利!正如我在我的問題的最後一個代碼塊中所做的那樣,只有我在構造函數中返回了「new new xxxx」,這沒有奏效。將它們移動到「創建」方法是一種魅力! – Codecraft

0

在這種情況下,我會一般:

  • 定義一些DAOInterface,有方法,如connectqueryfecthAll,...
    • 連接到數據庫中的所有類必須實現該接口
    • 這意味着你的mysql_daomysqli_dao ...會實現該接口

然後,與那些工作時類的主要優勢在於:

  • 您稍後將實例化爲$db變量或者mysql_daomysqli_dao,但總是得到實現DAOInterface
  • 這意味着你一定會認爲你可以調用所有這些方法,你$db對象


之後上的對象,只會有一個地方您必須在mysql_daomysqli_dao之間進行選擇:當您將這兩個參數之一實例化時,將結果分配給$db

然後,正如你所知道的那樣$db是一個實現了DAOInterface的對象,你肯定知道你將永遠能夠在該對象上調用相同的方法。

+0

這是我想出的解決方案之一(我只是沒有談論原始問題中的接口),但這仍然意味着我必須直接調用DAO,所以如果我想改變,就會有變化到使用數據庫的每個頁面中的調用代碼(不包括使用包含等)。 – Codecraft

+0

只要你所有的DAO實現了相同的接口,任何地方都不會有任何改變(除非你將DAO實例化並將其分配給$ db)*,只要所有DAO實現相同的接口:使用該接口方法的代碼將保持完全相同。 –

+0

我明白 - 我只是想變得更懶惰:-)實例化代碼始終是「新數據庫」,而不管它使用了哪個實際的DAO。 – Codecraft

3

爲什麼不直接使用PDO?它提供了與各種數據庫接口的統一方式(實際執行的查詢必須與目標數據庫一起編寫,但API無論連接的是何種數據庫都是相同的)。

+1

我個人討厭沒有需要的用戶創建的庫。重寫車輪。 – armandomiani

+0

我會研究它,但是可能發生的一個問題是我沒有託管我寫的所有內容,所以我並不總是能夠訪問PHP配置(有時我甚至沒有訪問PHP5的權限!) – Codecraft

+0

PHP 4不再支持,如果你有客戶仍在使用它,那麼我會傾向於敦促他們升級。爲了自己的保護,如果沒有別的,PHP 4包含的漏洞永遠不會被修復,使用它基本上會讓服務器很容易被攻擊。 – GordonM

0

爲了具備的功能是功能,您將需要傳遞和返回參數作爲在下面的示例引用:

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數據庫,但我相信你會找到一種方法來爲不同類型的數據庫創建一個對象。