【发布时间】:2017-06-07 14:15:54
【问题描述】:
在 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);
如果 DOMDocument 实例化它们,您似乎无法从扩展 DOMNode 或内置扩展类(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";
现在的争论 - 这是开发人员的意图并且文档具有误导性,还是应该发生错误和真正的继承?
【问题讨论】:
-
文档中甚至有一条注释显示构造函数应该调用
parent::__construct()。但我得到的结果和你一样。 -
您出于好奇使用了哪个版本的 PHP?
-
我使用 PHP 5.5.38
-
我一直尝试到 7.0 没有变化。并查看了 DOM ext 源代码,它看起来似乎在很长一段时间内都没有更改,因此 php 版本不太重要。
标签: php oop domdocument