如何创建“未知”类的对象?

时间:2013-03-04 21:39:15

标签: php oop

我有一个MySQL数据库和一个表格,每个记录都有idparametervalue(类似XML),可以说这个parameter列确定对象的“类型”。

对象在其他一些表中使用,具体取决于它们的类型,因此每个表都应以特定的方式处理。

因为“处理”有点普遍(我使用相同的函数)我创建了一个TObject类(不是抽象的但可能是),我继承了其他类;这个继承方法非常有用,这就是我使用面向对象编程的原因。例如,TObject有retrieve()方法从db获取所有必需的数据,而不是来自tobjects表的那些,但是其他类型依赖于类型,所以我在某些类中覆盖它。

我遇到的问题是,当我创建一个对象时,我不知道它应该是什么类。当然,我可以SELECT Parameter FROM tobjects WHERE id=$id,然后(使用switch)创建正确类的对象,并使用其retrieve()方法(每个类检索不同的数据,只有来自tobjects的数据是常见的)从数据库中获取数据,这导致我运行查询两次,并且在类外部工作的某些部分,这是有效的,但不是很温和。

最好的解决方案是,如果我可以创建一个TObject,然后在检索时,将对象的类更改为我需要的类,它将是TObject的后代,但我几乎可以肯定它是不可能的。

我的解决方案是,我运行第一个查询只是为了从tobjects中选择一个字段来确定对象的类吗?或者是否有在运行时更改对象类的技巧?

1 个答案:

答案 0 :(得分:1)

如果你理解你正在做的事情,我会采用以下方式:

PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE传递给PDOStatement::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
}