我有一个奇怪的行为扩展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?”。
答案 0 :(得分:2)
首先,你可能想知道你的第一个例子中发生了什么。为什么(地狱;))是前两个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变量内存中,它就属于你的类型。如果没有,你从父元素或文档“返回”它(不在你的某个变量中),它从其他一些内存中读取并返回作为 a DOMElement
这意味着,PHP不会在内存中保留大量DOMElement
个对象,因为文档中包含许多元素,但内部存在其他数据结构,当您与DOMDocument
交互时,PHP将创建这些对象是动态的(除非该对象已经创建并且仍然在可变内存中)。
所以这应该解释为什么前两个是DOMElement
($node
被重新分配,因此它们不再是PHP变量内存)而对于第三个节点,它仍然在记忆,因此没有创建。
通过这种解释,现在还应该更清楚限制的位置:即使您向文档添加了更具体的DOMElement
节点(例如 JavaScript
, JavaScriptLibrary
)它并不意味着你从DOM中取回它。因为DOM只是一个模型,可以保证给你一个DOMElement
而不是“你在那里填充的东西”。
我刚才谈到的内存中的这个结构,其中没有PHP对象存在但仍然表示所有元素,它基于一个名为libxml的库。 PHP使用这些。
因此,每次PHP基于DOMElement
的内部结构创建新对象时,它都使用相同名称的PHP类。
您可以通过注册基类的子类(例如DOMDocument
作为基类,JavaScriptLibrary
作为子类)来更改BTW中的类名,然后DOMDocument
将 - 在创建新对象实例时 - 请改用该类。
因此,我们不会在上面的示例变体中重新分配给$node
,而是注册一个不同的类:
$dom->registerNodeClass('DOMElement', 'JavaScriptLibrary');
foreach ($dom->childNodes as $childNode) {
echo get_class($childNode)."\n";
}
输出:
JavaScriptLibrary
JavaScriptLibrary
JavaScript
Etvoilà!只要PHP从内部存储器结构中创建那些 DOMElement
,就可以在已注册的类中获取它,这里是 JavaScriptLibrary
。
如果这仍然太有限你想要做什么,我知道处理这个的唯一方法是扩展DOMDocument
,在构造时自我引用(所以这个对象不会丢失),子类任何其他节点类型,对于任何添加,保留你在内存中添加的对象,以便它像你第三次经历的那样“按原样”返回。
如果你想快速开发,我建议你使用一个名为traits的PHP 5.4特性,因为大多数domdocument-extension-classes都是从DOMNode
延伸出来的,你不能为你自己的子类扩展,他们需要从他们的基类扩展,否则这将无法工作。由于PHP没有多重继承,因此traits可以帮助您在不需要为实例/对象管理创建的所有子类之间复制写代码。
还建议您熟悉DOMDocument
- 模型,以便了解如何添加和删除节点,以便管理内存。我不能说这是值得的工作,甚至是100%可能你尝试做的事情。