我设法使用 PHP DOM 实现来创建包含DOMElement
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" : "&nbsp;&nbsp;";
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 的无效使用