2012-01-19 118 views
4

我已經做了幾個項目,最近使用,我用了快一個關記錄查詢/更新數據庫對象的超類,並以適當類,如用戶類擴展。數據庫對象類PHP

我發現很多類我在寫有完全相同的方法:query_values(),更新(),刪除()等

於是我想出了一個構造函數,看起來像這樣一類:

public function __construct($table, $db_object, $record_id = null){ 
    $this->db = $db_object; // Database object with query methods 

    $this->table = $table; // The name of the database table 

    $this->get_column_data(); 

    if(!is_null($record_id)){ 
     // This retrieves all column values, 
     // stores into private $fields array property 
     $this->query_values($record_id); 
    } 
} 

和子類的構造函數如下:

public function __construct($db_object, $record_id = null){ 
    parent::__construct($this->table, $db_object, $record_id); 
} 

凡$表屬性在上面定義的,因爲我們應該知道的表的特定對象使用。現在

,所有常用的記錄管理方法是在一個地方,而具體到類的方法都被在各自的子類中定義。

我在這裏看到的最大缺點是所有的數據字段都被拉伸並封裝在$ fields屬性中,因此需要定義通用的get和set方法(通常我會這樣做),這幾乎否定了封裝*或者必須爲我們想要公開的每個屬性專門定義一個方法。

*示例: $ USER_ID = $用戶 - > ID; //不使用我的方法 與 $ USER_ID = $用戶 - > _ GET( '身份證'); //訪問的結果$用戶 - >域[「身份證」]

你認爲這是一個缺點,或加?目標是易於使用,面向對象(封裝),並且簡直太棒了!

+2

成就解鎖:直觀地實現[行數據網關模式](http://martinfowler.com/eaaCatalog/rowDataGateway.html) – Gordon

+0

@戈登 - 謝謝戈登,這證實了我的想法! – AVProgrammer

回答

2

嗯,你可以讓你的生活更輕鬆,並使用PHP的魔術超載__call方法來創建通用的getter和setter。您可以將以下方法添加到「數據庫對象超級類」中:

/** 
* Create magic getter and setter methods to access private $fields array 
*/ 
public function __call($method, $args) 
{ 
    $prefix = substr($method, 0, 3); 
    $prop = lcfirst(substr($method, 3)); 

    if (isset($this->fields[$prop])) { 

    if ($prefix == 'get') { 
     return $this->fields[$prop]; 
    } elseif ($prefix == 'set') { 
     if (! isset($args[0])) { 
     $msg = 'Missing argument: ' . get_class($this) . "::$method must specify a value"; 
     throw new InvalidArgumentException($msg); 
     } 
     $this->fields[$prop] = $args[0]; 
     return; 
    } 
    } 

    $msg = 'Invalid method: ' . get_class($this) . "::$method does not exist"; 
    throw new BadMethodCallException($msg); 
} 

因此,讓我解釋一下這裏發生了什麼。魔術__call方法將收到通話不匹配的對象的具體方法之一任何對象方法。它作爲參數接收被調用的方法的名稱和它的參數數組。

上面的__call方法快速執行substr檢查以查看該方法是「getter」還是「setter」(使用方法名的前三個字母)。它期望您的$fields數組存儲小寫的「屬性」名稱(lcfirst),並將setter/getter前綴後的所有內容用作期望的屬性名稱。

如果某個屬性與getter方法匹配,則返回該屬性。如果不是,則拋出SplException BadMethodCallException。這是自PHP中包含Spl異常以來的最佳做法。

同樣,如果沒有指定參數,setter方法也會拋出SplException InvalidArgumentException

PHP的魔法會改變你的生活。您還可以使用__get__set以類似方式分配$fields數組值,而不進行僞造方法調用。興奮:)

0

您可以通過實現你的目標的幾個magic methods有兩全其美。例如,通過實施__get__set__isset可以使屬性訪問看「天然」(例如$user->id),而在同一時間不具有在每個單獨的子類來定義的屬性。

例如,__get的實現可以在運行時檢查$fields成員以查看您試圖獲取的屬性是否對特定對象類有效。您可以在基類中一次寫這個通用的實現,只是填充$fields因此,使其與任何類型的對象的工作。這實際上就是所有現代化的地圖繪製工具所做的,包括所有您聽說過的PHP框架。

順便說一句,我希望你緩存每個類的表架構內get_column_data。每次構建相應類的對象時,爲同一個表的模式重新查詢數據庫將會非常低效。

1

主要有兩種途徑:

PHP文件創建

所有大ORM /數據庫項目,我知道,不要讓用戶編寫所有的getter方法自己。 DoctrinePropel使用自動生成器在調用命令行腳本時使用getter方法創建真正的PHP文件。這些文件包含所謂的Base方法,這些方法可以通過一些類自動擴展,您將自己的代碼放入(因此重新創建基類不會刪除自己的代碼)。

文件創建的優勢是你有一個定義良好的界面(當可調用方法在源代碼中不可見時,有些人不喜歡它)。

魔術方法/超載

數據庫引擎在我的客戶端的應用程序所使用的魔法方法已經看到模擬 getter和setter。你可以使用神奇的方法__get()__set()__call()(稱爲「overloading」 in PHP documentation)。使用哪種方法取決於您希望如何訪問您的值(最常用的$obj->property$obj->getProperty())。

重載的優點是您不需要編寫複雜的PHP代碼生成器,也不需要每次更改數據庫設計時都調用命令行腳本。