2013-03-04 101 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