2013-03-04 105 views
0

我有一個MySQL數據庫和一個表,其中每個記錄都有它的id,parameter,value(類似於XML),並且可以說這個parameter列確定了一個對象的「類型」。如何創建「未知」類的對象?

這些對象在其他一些表中使用,具體取決於它們的類型,因此應該以特定方式處理它們中的每一個。因爲「處理」有點常見(我使用相同的函數),我創建了一個TObject類(不是抽象的,但可以是),我從中繼承了其他類;這種繼承方法非常有用,這就是我使用面向對象編程的原因。例如TObject有retrieve()方法,它從db獲取所有必要的數據,而不是那些在tobjects表中,但也有一些類型依賴的數據,所以我在一些類中覆蓋它。

我遇到的問題是,當我創建一個對象時,我不知道它應該是什麼類。當然,我可以SELECT Parameter FROM tobjects WHERE id=$id,然後(與switch)創建適當的類的對象,並使用它的retrieve()方法(每個類檢索不同的數據,只有那些來自tobjects的是常見的)才能從數據庫中獲取數據,這導致我兩次運行查詢和一部分工作以外的工作,這是可行的,但並不溫和。

最好的解決方案是,如果我可以創建一個TObject,然後在檢索時將對象的類更改爲我需要的類,這將是TObject的後代,但我幾乎可以肯定這是不可能的。

是我的解決方案,我運行第一個查詢只是爲了選擇一個字段從只有確定對象的類正確?或者是否有一種技巧在運行時改變對象的類?

+1

我想創建,確實檢查數據工廠方法(其中應包括你的'Parameter'已經)創建一個類型的對象需要。工廠方法是你的朋友,特別是當代碼庫增長的時候。然而,從長遠來看,檢索「所有不同對象的國王」的方法可能無法維持...... – Wrikken 2013-03-04 21:43:08

+0

@Wrikken,謝謝你的評論。這似乎是唯一的想法... – Voitcus 2013-03-04 22:07:18

+0

儘管你[可以(但不應該)在運行時轉換對象](http:// stackoverflow。com/questions/3243900/convert-cast-an-stdclass-object-to-another-class/3243949#3243949)工廠是最理智的方法。 – Gordon 2013-03-06 09:23:59

回答

1

如果明白你在做正確的東西,在這裏我會處理這個方式:

傳遞PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPEPDOStatement::fetch()的第一個參數將返回PDOStatement::fetchColumn(0)類的對象 - 換句話說,它決定了類名從結果集的第一列的值中實例化。

要充分利用這一點,您需要JOIN tobjects ON targetTable.objectType = tobjects.id並選擇tobjects.Parameter作爲結果集中的第一列。如果Parameter列已經將數據庫對象類型映射到類名的1:1映射,那麼這就是您所需要做的,但是我不確定這是否是這種情況,並且可能不應該這樣做,因爲它使在以後的日子裏更難以替代另一個班級。

爲了克服這個限制,我建議你創建一個臨時表,當你第一次連接數據庫,這Parameter值映射到類名,您可以JOIN到查詢來獲取目標類的名稱。

所以流量會去是這樣的:

// Set up the connection 
$db = new PDO('mysql:yourDSNhere'); 
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); 

// Create a temp table to store the mapping 
$db->query(" 
    CREATE TEMPORARY TABLE `objectMappings` (
    `Parameter` INT NOT NULL PRIMARY KEY, 
    `ClassName` VARCHAR(255) 
) ENGINE=MEMORY 
"); 

// A mapping of Parameter IDs to class names 
$classMap = array(
    1 => 'Class1', 
    2 => 'Class2', 
    3 => 'Class3', 
    // ... 
); 

// Build a query string and insert 
$rows = array(); 
foreach ($classMap as $paramId => $className) { 
    // this data is hard-coded so it shouldn't need further sanitization 
    $rows[] = "($paramId, '$className')"; 
} 

$db->query(" 
    INSERT INTO `objectMappings` 
    (`Parameter`, `ClassName`) 
    VALUES 
    ".implode(', 
    ', $rows)." 
"); 

// ... 

// When you want to retrieve some data 
$result = $db->query(" 
    SELECT m.ClassName, t.* 
    FROM targetTable t 
    JOIN tobjects o ON t.objectType = o.id 
    JOIN objectMappings m ON o.Parameter = m.Parameter 
    WHERE t.someCol = 'some value' 
"); 

while ($obj = $result->fetch(PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE)) { 
    // $obj now has the correct type, do stuff with it here 
} 
+0

哇!我還沒有測試過,但這個想法很棒。我錯過了'FETCH_CLASS'和'FETCH_CLASSTYPE'。這正是我需要的。謝謝! – Voitcus 2013-03-06 11:59:51