gpt4 book ai didi

php - 未在扩展的 PHP DOMElement 上调用构造函数

转载 作者:塔克拉玛干 更新时间:2023-11-03 05:46:32 24 4
gpt4 key购买 nike

在 PHP 中扩展 DOMElement 时,不会调用子类的构造函数。就预期行为而言,文档中没有任何内容向我发出警告,但也许我遗漏了一些东西。这是一个简单的测试用例....

 class SillyTestClass extends DOMElement{
public $foo=null;
public function __construct($name,$value=null,$namespace=null){
echo "calling custom construct....";
$this->foo="bar";
parent::__construct($name,$value,$namespace);
}
public function sayHello(){
echo "Why, hello there!";
}
}

$doc=new DOMDocument();
$doc->registerNodeClass('DOMElement','SillyTestClass');
$doc->loadHTML("<div><h1>Sample</h1></div>");
//THIS WORKS! CUSTOM CLASS BEING USED
$doc->documentElement->firstChild->sayHello();

//THIS IS STILL NULL:( Never set by construct, no message saying construct was called either
echo $doc->documentElement->firstChild->foo;

当然如果我自己实例化它就好了...

$elm=new SillyTestClass("foo","Hi there");
//WORKS! Outputs "bar";
echo $elm->foo;

为什么当我用 DOMDocument 注册节点类时,它不调用 __construct,即使它以其他方式为我提供了正确的继承?

更新 对于真正好奇的人或了解 C 的人

============================================ ===========================调查....

这是取自 PHP src on github 的 DOM 扩展源

如果你要创建一个元素,这是发生的事件链::

document.c :: dom_document_create_element
| //uses libxml to generate a new DOMNode
| node = xmlNewDocNode(docp, NULL, (xmlChar *) name, (xmlChar *) value);

// that node is then sent to
php_dom.c :: php_dom_create_object
|
| //the node type is used to figure out what extension class to use
| switch (obj->type) {...
|
| //that class is used to instance an object
| if (domobj && domobj->document) {
| ce = dom_get_doc_classmap(domobj->document, ce);
| }
object_init_ex(return_value, ce);

看起来您并没有从扩展 DOMNode 获得真正的继承,或者如果 DOMDocument 实例化它们,它是内置在扩展类(DOMElement、DOMText)中的。在这种情况下,首先创建 libxml 节点,然后添加我们的类属性。

这看起来很不幸而且不可能绕过,因为即使您将 importNode 导入到文档中,它也会实例化一个新节点。示例

class extendsDE extends DOMElement{
public $constructWasCalled=false;
public function __construct($name){
parent::__construct($name);
$this->constructWasCalled=true;
}
}

class extendsDD extends DOMDocument{

public function __construct(){
parent::__construct();
$this->registerNodeClass("DOMElement","extendsDE");
}
//@override
public function createElement($name){
$elm=new extendsDE($name);
echo "Element construct called when we create=";
echo $elm->constructWasCalled?"true":"false";
return $this->importNode($elm);
}
}

$doc=new extendsDD();
$node=$doc->createElement("div");
echo "<br/>";
echo "But then when we import into document, a new element is created and construct called= ";
echo $node->constructWasCalled?"true":"false";

现在的争论 - 这是开发人员的意图并且文档具有误导性,还是它是一个错误并且应该发生真正的继承?

最佳答案

到目前为止,我已经在某些情况下找到了解决此问题的方法。 DOMNodes 保存在内存中,所以只要你能将它一次性放入文档中(调用你的构造函数),那么无论你用它做什么或之后你如何访问它都可以......

这是一个示例,我们可以在其中调用构造并且仍然可以处理文档

class extendsDE extends DOMElement{
public $constructWasCalled=false;
public function __construct($name){
parent::__construct($name);
$this->constructWasCalled=true;
}
}

$doc=new DOMDocument();
$doc->registerNodeClass("DOMElement","extendsDE");
$doc->loadHTML("<div></div>");

//append a node we create manually rather than through createElement
$node=$doc->getElementsByTagName('div')->item(0)->appendChild(new extendsDE("p"));
$node->nodeValue="Was my construct called?";
echo "<br/>";
echo "A new element was appended and construct called= ";
echo $node->constructWasCalled?"true":"false";
echo "<br/>";
echo "Okay but what happens if I retrieve that node some other way..";
echo "<br/>";
echo "what if I get that element through selectors. Custom property still set from constructor=";
echo $doc->getElementsByTagName('p')->item(0)->constructWasCalled?"true":"false";
echo "<br/>";
echo "what if I get that element through relationships. Custom property still set from constructor=";
echo $doc->getElementsByTagName('div')->item(0)->childNodes->item(0)->constructWasCalled?"true":"false";

要点:

这只有在您创建所有元素时才有效。如果您使用 $document->loadHTML($html) 加载 HTML 标记,您的扩展构造函数将不会被调用。到目前为止,我只能想到解决这个问题的破解方法,比如加载标记,然后将每个节点循环到实例副本并插入它们。绝对有可能,但速度很慢......

关于php - 未在扩展的 PHP DOMElement 上调用构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41800107/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com