如何创建一个“未知”对象类


How to create an object of "unknown" class?

我有一个MySQL数据库和一个表对象,其中每个记录都有其id, parameter, value(类似于XML),并且可以说这个parameter列确定了对象的"类型"。

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

因为"处理"有点常见(我使用相同的函数),我创建了一个object类(不是抽象的,但可以是),从中继承其他类;这种继承方法非常有用,这就是我使用面向对象编程的原因。例如,TObject有retrieve()方法,从db获得所有必要的数据,而不是对象表中的数据,但其他的,这是类型依赖的,所以我在一些类中覆盖它。

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

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

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

如果你明白你在做什么是正确的,下面是我的方法:

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
}