PHP DOMDocument在克隆/返回时更改节点类实例?

PHP DOMDocument在克隆/返回时更改节点类实例?,php,xml,dom,Php,Xml,Dom,我设法使用PHPDOM实现来创建包含DomeElements子类的自定义文档树,但我发现了一件非常奇怪的事情:克隆或返回DOMDocument似乎会改变子节点类 基本示例 class Section extends DOMElement { public function __construct($name, $value = null, $uri = null) { parent::__construct($name, $value, $uri); } } class P

我设法使用PHPDOM实现来创建包含
DomeElement
s子类的自定义文档树,但我发现了一件非常奇怪的事情:克隆或返回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);
将输出

Using new instance - Inside function root DOMElement first child Section Using new instance - Inside function (clone) root DOMElement first child DOMElement Returned doc in global scope root DOMElement first child DOMElement Using global scope instance - Inside function root DOMElement first child Section Using global scope instance - Inside function (clone) root DOMElement first child DOMElement Modified doc in global scope root DOMElement first child DOMElement 使用新实例-内部函数 根穹隆 第一儿童组 使用新实例-内部函数(克隆) 根穹隆 第一个孩子 全局范围内返回的单据 根穹隆 第一个孩子 使用全局作用域实例-内部函数 根穹隆 第一儿童组 使用全局作用域实例-内部函数(克隆) 根穹隆 第一个孩子 在全局范围内修改单据 根穹隆 第一个孩子 当文档被克隆或返回(甚至通过引用)时,第一个子元素的类从
节更改为简单的
doElement

  • 我的PHP版本是5.3.10,但在5.4下也会出现相同的行为
  • 使用DOMDocument::registerNodeClass将通过注册的节点类转换
    DomeElement
    ,但我有多个子类
    DomeElement
我的问题并不是要找到一个解决方法或不同的解决方案,但我想了解这里发生了什么,以及子节点通过什么机制进行转换

编辑:我发现了一个与此问题相关的错误报告(2年):。
建议的解决方法工作得很好,但仍然不清楚这是真正的bug还是DOM API的无效使用。当您使用
新段落
新节
时,您需要将它们存储在单独的数组中以将它们保存在内存中,这样
DOMDocument
就不仅仅使用它的默认类

错误报告是准确的,我认为PHP中的
DOM
的整个实现是有缺陷的

将对象的副本保存在别处是内存密集型的,不管怎样使用DOM也是如此。由于存在许多缺陷,我个人正在努力使一个像样的实现正常工作,所以你不是唯一一个:)