php - 扩展 DOMElement

标签 php xml dom

我在扩展 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 节点(例如 JavaScriptJavaScriptLibrary)这并不意味着您可以从 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/

相关文章:

sql - 更新 SQL Server XML 列中的 XML 属性

javascript - 稍后如何触发 native 点击操作(重播事件)?

php - 从 XML 节点 PHP DOM 中删除所有子节点

php - 如何不让包裹路线重载主要路线?

javascript - 我的登录系统中的 user.php 不会响应

xml - Visual Studio 2013 IntelliSense 无法使用特定的 web.config 文件

javascript - 迭代表更新每个单元格的货币 javascript/Jquery

php - 如何按类别 ID 包含两个文件

php - 通过 PHP cURL 连接时出现 SSL3_READ_BYTES 错误

android - 我们如何将 Canvas 上的绘图与 Android 中的预定义图像进行比较?