我最近一直在摆弄DOMDocument,我注意到为了将元素从一个文档传输到下一个文档,我必须在目标DOMDocument
上调用$DOMDocument->importNode()
。
然而,我遇到了一些奇怪的问题,一旦原始文档被销毁,克隆的元素就会出现错误行为。
例如,这里有一些可爱的工作代码:
$dom1 = new DOMDocument;
$dom2 = new DOMDocument;
$dom2->loadHTML('<div id="div"><span class="inner"></span></div>');
$div = $dom2->getElementById('div');
$children = $dom1->importNode( $div, true )->childNodes;
echo $children->item(0)->tagName; // Output: "span"
下面是一个演示:http://codepad.viper-7.com/pjd9Ty
当我在原始文档超出范围后尝试使用元素时,问题就出现了:
global $dom;
$dom = new DOMDocument;
function get_div_children () {
global $dom;
$local_dom = new DOMDocument;
$local_dom->loadHTML('<div id="div"><span class="inner"></span></div>');
$div = $local_dom->getElementById('div');
return $dom->importNode( $div, true )->childNodes;
}
echo get_div_children()->item(0)->tagName;
以上结果导致以下错误:
PHP警告:无法获取
DOMElement
。节点不再存在于中
PHP注意事项:未定义的属性:DOMElement::$tagName
在。。。
下面是一个演示:http://codepad.viper-7.com/c0kqOA
我的问题有两个:
即使在原始文档被销毁后,返回的元素也不应该存在吗?因为它们被克隆到了当前文档中?
解决方法。由于各种原因,我必须在原始文档被销毁之后,但在实际将它们插入其他
DOMDocument
的DOM之前,对这些元素进行操作。有什么办法可以做到这一点吗?
澄清:我知道,如果元素被插入到DOM中,它的行为会像预期的那样。但是,如上所述,我的设置要求在将元素插入DOM之前对其进行操作(长话短说)。考虑到这里的第一个例子是有效的,并且在DOM之外操纵元素是JavaScript中的标准过程,这在这里不应该也是可能的吗?
克隆的节点有对$dom的引用,但$dom没有。当调用上下文发生更改时,内部PHP垃圾收集器会销毁此类节点。只有一种方法可以创建此引用:$dom->documentElement->appendChild($node)
。
所以,使用这样的代码(static关键字将防止垃圾收集器破坏您的变量):
global $dom;
$dom = new DOMDocument;
function get_div_children () {
global $dom;
$local_dom = new DOMDocument;
$local_dom->loadHTML('<div id="div"><span class="inner"></span></div>');
$div = $local_dom->getElementById('div');
static $nodes;
$nodes = $dom->importNode( $div, true )->childNodes;
return $nodes;
}
echo get_div_children()->item(0)->tagName;