2

我设法使用 PHP DOM 实现来创建包含DOMElements 子类的自定义文档树,但我发现一些非常奇怪的事情:克隆或返回 DOMDocument 似乎会更改子节点类。

基本示例

class Section extends DOMElement
{
  public function __construct($name, $value = null, $uri = null)
  {
    parent::__construct($name, $value, $uri);
  }
}

class Paragraph extends DOMElement
{
  public function __construct($name, $value = null, $uri = null)
  {
    parent::__construct($name, $value, $uri);
  }
}

function display_doc($label, DOMDocument $doc)
{
  $endl = (PHP_SAPI == "cli") ? "\n" : "<br />";
  $pad  = (PHP_SAPI == "cli") ? "\t" : "  ";
  echo ($label . $endl);

  $root = $doc->documentElement;
  echo ($pad . "root " . get_class($root) . $endl);
  echo ($pad . "first child " . get_class($root->firstChild) . $endl);
}

function test_dom($name, DOMDocument &$instance = null)
{
  $doc = ($instance) ? $instance : new DOMDocument("1.0", "utf-8");
  $root = $doc->appendChild($doc->createElement("root"));
  $section = new Section("section");

  $root->appendChild($section);
  $paragraph = new Paragraph("para");
  $section->appendChild($paragraph);

  $clone = clone $doc;

  display_doc($name . " - Inside function", $doc);
  display_doc($name . " - Inside function (clone)", $clone);

  return $doc;
}

$doc = test_dom("Using new instance");
display_doc("Returned doc in global scope", $doc);

$doc2 = new DOMDocument("1.0", "utf-8");
test_dom("Using global scope instance", $doc2);
display_doc("Modified doc in global scope", $doc2);

将输出

使用新实例 - 内部函数
    根 DOMElement
    第一个孩子节
使用新实例 - 内部函数(克隆)
    根 DOMElement
    第一个子 DOMElement
在全局范围内返回文档
    根 DOMElement
    第一个子 DOMElement
使用全局范围实例 - 内部函数
    根 DOMElement
    第一个孩子节
使用全局范围实例 - 内部函数(克隆)
    根 DOMElement
    第一个子 DOMElement
全局范围内的修改文档
    根 DOMElement
    第一个子 DOMElement

当文档被克隆或返回(甚至通过引用)时,第一个孩子的类从Section变为简单DOMElement

  • 我的 PHP 版本是 5.3.10,但在 5.4 下发生相同的行为
  • 使用 DOMDocument::registerNodeClass 将由DOMElement注册的节点类进行转换,但我有多个子类DOMElement

我的问题并不是真正寻找解决方法或不同的解决方案,而是我想了解这里发生了什么以及通过哪种机制转换子节点。

编辑:我发现了与此问题相关的错误报告(2 岁):http: //www.mail-archive.com/php-bugs@lists.php.net/msg134710.html。建议的解决方法效果很好,但尚不清楚它是真正的错误还是对 DOM API 的无效使用

4

1 回答 1

1

当您使用时new Paragraphnew Section您需要将它们存储在一个单独的数组中以将它们保存在内存中,这样DOMDocument就不仅仅是使用它的默认类。

错误报告是准确的,我认为DOMPHP 的整个实现存在缺陷。

在别处保存对象的副本是内存密集型的,无论如何使用 DOM 也是如此。由于存在许多缺陷,我个人正在努力让一个体面的实施工作,所以你不是唯一的:)

于 2014-02-22T12:08:49.987 回答