2

我在扩展 PHP DOMElements 时遇到了一个奇怪的行为:

class JavaScript extends DOMElement {
}

class JavaScriptLibrary extends DOMElement {
}

$dom = new DOMDocument();

$node = new JavaScript('script');
$dom->appendChild($node);

$node = new JavaScriptLibrary('script');
$dom->appendChild($node);

$node = new JavaScript('script');
$dom->appendChild($node);

foreach ($dom->childNodes as $childNode) {
    echo get_class($childNode)."\n";
}

预期的:

JavaScript
JavaScriptLibrary
JavaScript

结果:

DOMElement
DOMElement
JavaScript

这里会发生什么?

如果我这样做:

addElement($dom, new JavaScript('script'));
addElement($dom, new JavaScriptLibrary('script'));
addElement($dom, new JavaScript('script'));

function addElement($dom, $node){
    $dom->appendChild($node);
}

结果将是

DOMElement
DOMElement
DOMElement

我如何在不使用 ->createElement 的情况下做到这一点,例如“我如何扩展 PHP DOMElement? ”。

4

1 回答 1

2

首先,您可能想知道在您的第一个示例中发生了什么。为什么(地狱;))是前两个 aDOMElement和第三个 a JavaScript

那是因为该$node变量到目前为止还没有被重新分配或取消设置。如果您取消设置或重新分配它,输出会有所不同:

$node = 1; # re-assing to (int) 1

foreach ($dom->childNodes as $childNode) {
    echo get_class($childNode)."\n";
}

输出:

DOMElement
DOMElement
DOMElement

如您所见,第三个现在就像前两个一样。

这可能已经给你一个指针。只要您的 DOMNode对象保存在 PHP 变量内存中,它就属于您的类型。如果不是,并且您从父元素或文档中“返回”它(没有在您的某个变量中包含它),它会从其他一些内存中读取并作为DOMElement.

这意味着,PHP 不会DOMElement仅仅因为文档有那么多元素而在内存中保留大量对象,但内部还有一些其他数据结构,当您与 交互时DOMDocument,PHP 将即时创建这些对象(除非该对象已经创建并仍然在可变内存中)。

所以这应该解释为什么前两个是DOMElement$node被重新分配,所以它们不再在 PHP-variable-memory 中),而对于第三个节点,它仍然在内存中,因此没有被创建。

有了这个解释,现在也应该更清楚限制在哪里:即使您DOMElement向文档添加了更具体的节点(例如JavaScript, JavaScriptLibrary),但这并不意味着您从 DOM 中获取了它。因为 DOM 只是一个模型,它保证给你一个DOMElement而不是“你塞在那里的东西”。

我刚才谈到的内存中的这种结构,其中不存在 PHP 对象但仍然表示所有元素,它基于一个名为 libxml 的库。PHP利用了这些。

因此,每次 PHP 根据这些内部结构创建一个新对象时,DOMElement它都会使用同名的 PHP 类。

顺便说一句,您可以通过注册基类的子类(例如DOMDocument作为基类和JavaScriptLibrary子类)来更改类名,然后DOMDocument在创建新对象实例时使用该类。

$node因此,我们注册了一个不同的类,而不是在上面的 example-variation中重新分配 to :

$dom->registerNodeClass('DOMElement', 'JavaScriptLibrary');

foreach ($dom->childNodes as $childNode) {
    echo get_class($childNode)."\n";
}

输出:

JavaScriptLibrary
JavaScriptLibrary
JavaScript

等等瞧!只要 PHP 从内部内存结构中创建那些DOMElements,你就可以在注册的类中得到它,这里JavaScriptLibrary.

如果这对于你想做的事情来说仍然太有限DOMDocument,我知道的唯一处理方法是扩展,在构造时自引用它(所以这个对象不会丢失),子类化任何其他节点类型,对于任何添加,请将您添加的对象保留在内存中,以便它像您在第三个对象中遇到的那样“按原样”返回。

如果你想快速开发,我建议你使用 PHP 5.4 的特性,因为即使大多数 domdocument-extension-classes 扩展自DOMNode,你不能为你自己的子类,它们需要从它们的基础扩展-class 否则这将不起作用。由于 PHP 没有多重继承,因此特性可以帮助您避免在您需要为实例/对象管理创建的所有子类之间重复编写代码。

还建议您对 -Model 有很好的了解,DOMDocument以便您了解如何添加和删除节点,以便您可以管理内存。我不能说它是否值得这项工作,或者你尝试做的事情是否有 100% 的可能。

于 2013-06-23T15:17:16.173 回答