我在扩展 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 的情况下执行此操作,如此处的“How can I extend PHP DOMElement? ”。
最佳答案
首先,您可能想知道第一个示例中发生了什么。为什么(见鬼;))前两个是 DOMElement
而第三个是 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
交互时code>,PHP 将动态创建这些对象(除非该对象已经创建并且仍然位于可变内存中)。
所以这应该解释为什么前两个是 DOMElement
($node
被重新分配,因此它们不再位于 PHP 变量内存中),而对于第三个节点,它仍然在内存中,因此没有创建。
有了这个解释,现在应该更清楚限制在哪里:即使您向文档添加了更具体的 DOMElement
节点(例如 JavaScript
、JavaScriptLibrary
)这并不意味着您可以从 DOM 中获取它。因为 DOM 只是一个保证返回 DOMElement
的模型,而不是“您填充到其中的内容”。
我刚才谈到的内存结构基于一个名为 libxml 的库,其中不存在 PHP 对象,但仍然表示所有元素。 PHP 利用了这些。
因此,每次 PHP 根据这些内部结构为 DOMElement
创建新对象时,它都会使用同名的 PHP 类。
顺便说一句,您可以通过注册基类的子类(例如 DOMDocument
作为基类,JavaScriptLibrary
作为子类)来更改此处的类名,然后DOMDocument
将在创建新对象实例时使用该类。
因此,我们注册了一个不同的类,而不是在上面的示例变体中重新分配给 $node
:
$dom->registerNodeClass('DOMElement', 'JavaScriptLibrary');
foreach ($dom->childNodes as $childNode) {
echo get_class($childNode)."\n";
}
输出:
JavaScriptLibrary
JavaScriptLibrary
JavaScript
瞧瞧!;只要 PHP 从内部内存结构创建这些 DOMElement
,您就可以在注册的类中获取它,这里是 JavaScriptLibrary
.
如果这对于您想要做的事情来说仍然太有限,我知道处理这个问题的唯一方法是扩展DOMDocument
,当构造(这样这个对象就不会丢失),子类化任何其他节点类型,对于任何添加,将您添加的对象保留在内存中,以便它确实返回“按原样”,就像您在第三个节点中经历的那样。
如果您想快速开发,我建议您使用称为特征的 PHP 5.4 功能,因为即使大多数 domdocument-extension-classes 都从 DOMNode
扩展,您也不能为自己的子类,它们需要从其基类扩展,否则这将不起作用。由于 PHP 没有多重继承,因此特征可以帮助您避免在为实例/对象管理创建的所有子类之间重复编写代码。
还建议您充分了解 DOMDocument
-模型,以便您了解如何添加和删除节点,从而可以管理内存。我不能说这是否值得付出努力,甚至不能说是否 100% 可能实现您尝试做的事情。
关于php - 扩展 DOMElement,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17260190/