Implement Dom\HTMLElement class

This commit is contained in:
Niels Dossche 2024-04-27 21:23:29 +02:00
parent 78401ba867
commit 48c9f1e2c3
11 changed files with 58 additions and 20 deletions

View file

@ -44,6 +44,7 @@ extern PHP_DOM_EXPORT zend_class_entry *dom_attr_class_entry;
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_attr_class_entry; extern PHP_DOM_EXPORT zend_class_entry *dom_modern_attr_class_entry;
extern PHP_DOM_EXPORT zend_class_entry *dom_element_class_entry; extern PHP_DOM_EXPORT zend_class_entry *dom_element_class_entry;
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_element_class_entry; extern PHP_DOM_EXPORT zend_class_entry *dom_modern_element_class_entry;
extern PHP_DOM_EXPORT zend_class_entry *dom_html_element_class_entry;
extern PHP_DOM_EXPORT zend_class_entry *dom_text_class_entry; extern PHP_DOM_EXPORT zend_class_entry *dom_text_class_entry;
extern PHP_DOM_EXPORT zend_class_entry *dom_modern_text_class_entry; extern PHP_DOM_EXPORT zend_class_entry *dom_modern_text_class_entry;
extern PHP_DOM_EXPORT zend_class_entry *dom_comment_class_entry; extern PHP_DOM_EXPORT zend_class_entry *dom_comment_class_entry;

View file

@ -1423,7 +1423,8 @@ zend_result dom_html_document_body_write(dom_object *obj, zval *newval)
dom_object *newval_intern = Z_DOMOBJ_P(newval); dom_object *newval_intern = Z_DOMOBJ_P(newval);
if (newval_intern->ptr != NULL) { if (newval_intern->ptr != NULL) {
xmlNodePtr newval_node = ((php_libxml_node_ptr *) newval_intern->ptr)->node; xmlNodePtr newval_node = ((php_libxml_node_ptr *) newval_intern->ptr)->node;
if (php_dom_ns_is_fast(newval_node, php_dom_ns_is_html_magic_token) && dom_accept_body_name(newval_node->name)) { /* Note: because this property has type HTMLElement, we know the namespace is correct. */
if (dom_accept_body_name(newval_node->name)) {
/* 2. If the new value is the same as the body element, return. */ /* 2. If the new value is the same as the body element, return. */
const xmlNode *current_body_element = dom_html_document_element_read_raw(docp, dom_accept_body_name); const xmlNode *current_body_element = dom_html_document_element_read_raw(docp, dom_accept_body_name);
if (current_body_element == newval_node) { if (current_body_element == newval_node) {

View file

@ -47,7 +47,6 @@ static zend_always_inline zend_class_entry *dom_get_dtd_namednodemap_ce(bool mod
DOM_DEF_GET_CE_FUNC(node) DOM_DEF_GET_CE_FUNC(node)
DOM_DEF_GET_CE_FUNC(documenttype) DOM_DEF_GET_CE_FUNC(documenttype)
DOM_DEF_GET_CE_FUNC(element)
DOM_DEF_GET_CE_FUNC(attr) DOM_DEF_GET_CE_FUNC(attr)
DOM_DEF_GET_CE_FUNC(entity) DOM_DEF_GET_CE_FUNC(entity)
DOM_DEF_GET_CE_FUNC(entityreference) DOM_DEF_GET_CE_FUNC(entityreference)

View file

@ -63,6 +63,7 @@ PHP_DOM_EXPORT zend_class_entry *dom_attr_class_entry;
PHP_DOM_EXPORT zend_class_entry *dom_modern_attr_class_entry; PHP_DOM_EXPORT zend_class_entry *dom_modern_attr_class_entry;
PHP_DOM_EXPORT zend_class_entry *dom_element_class_entry; PHP_DOM_EXPORT zend_class_entry *dom_element_class_entry;
PHP_DOM_EXPORT zend_class_entry *dom_modern_element_class_entry; PHP_DOM_EXPORT zend_class_entry *dom_modern_element_class_entry;
PHP_DOM_EXPORT zend_class_entry *dom_html_element_class_entry;
PHP_DOM_EXPORT zend_class_entry *dom_text_class_entry; PHP_DOM_EXPORT zend_class_entry *dom_text_class_entry;
PHP_DOM_EXPORT zend_class_entry *dom_modern_text_class_entry; PHP_DOM_EXPORT zend_class_entry *dom_modern_text_class_entry;
PHP_DOM_EXPORT zend_class_entry *dom_comment_class_entry; PHP_DOM_EXPORT zend_class_entry *dom_comment_class_entry;
@ -1042,6 +1043,11 @@ PHP_MINIT_FUNCTION(dom)
DOM_OVERWRITE_PROP_HANDLER(&dom_modern_element_prop_handlers, "textContent", dom_node_text_content_read, dom_node_text_content_write); DOM_OVERWRITE_PROP_HANDLER(&dom_modern_element_prop_handlers, "textContent", dom_node_text_content_read, dom_node_text_content_write);
zend_hash_add_new_ptr(&classes, dom_modern_element_class_entry->name, &dom_modern_element_prop_handlers); zend_hash_add_new_ptr(&classes, dom_modern_element_class_entry->name, &dom_modern_element_prop_handlers);
dom_html_element_class_entry = register_class_Dom_HTMLElement(dom_modern_element_class_entry);
dom_html_element_class_entry->create_object = dom_objects_new;
dom_html_element_class_entry->default_object_handlers = &dom_object_handlers;
zend_hash_add_new_ptr(&classes, dom_html_element_class_entry->name, &dom_modern_element_prop_handlers);
dom_text_class_entry = register_class_DOMText(dom_characterdata_class_entry); dom_text_class_entry = register_class_DOMText(dom_characterdata_class_entry);
dom_text_class_entry->create_object = dom_objects_new; dom_text_class_entry->create_object = dom_objects_new;
dom_text_class_entry->default_object_handlers = &dom_object_handlers; dom_text_class_entry->default_object_handlers = &dom_object_handlers;
@ -1541,6 +1547,19 @@ void php_dom_create_iterator(zval *return_value, dom_iterator_type iterator_type
} }
/* }}} */ /* }}} */
static zend_always_inline zend_class_entry *dom_get_element_ce(const xmlNode *node, bool modern)
{
if (modern) {
if (php_dom_ns_is_fast(node, php_dom_ns_is_html_magic_token)) {
return dom_html_element_class_entry;
} else {
return dom_modern_element_class_entry;
}
} else {
return dom_element_class_entry;
}
}
/* {{{ php_dom_create_object */ /* {{{ php_dom_create_object */
PHP_DOM_EXPORT bool php_dom_create_object(xmlNodePtr obj, zval *return_value, dom_object *domobj) PHP_DOM_EXPORT bool php_dom_create_object(xmlNodePtr obj, zval *return_value, dom_object *domobj)
{ {
@ -1572,7 +1591,7 @@ PHP_DOM_EXPORT bool php_dom_create_object(xmlNodePtr obj, zval *return_value, do
} }
case XML_ELEMENT_NODE: case XML_ELEMENT_NODE:
{ {
ce = dom_get_element_ce(modern); ce = dom_get_element_ce(obj, modern);
break; break;
} }
case XML_ATTRIBUTE_NODE: case XML_ATTRIBUTE_NODE:

View file

@ -1374,6 +1374,10 @@ namespace Dom
public function replaceChildren(Node|string ...$nodes): void {} public function replaceChildren(Node|string ...$nodes): void {}
} }
class HTMLElement extends Element
{
}
class Attr extends Node class Attr extends Node
{ {
/** @readonly */ /** @readonly */
@ -1581,9 +1585,9 @@ namespace Dom
public function importLegacyNode(\DOMNode $node, bool $deep = false): Node {} public function importLegacyNode(\DOMNode $node, bool $deep = false): Node {}
public ?Element $body; public ?HTMLElement $body;
/** @readonly */ /** @readonly */
public ?Element $head; public ?HTMLElement $head;
public string $title; public string $title;
} }

View file

@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead. /* This is a generated file, edit the .stub.php file instead.
* Stub hash: 7a2c28838f431eff28dea8cc5356dbcd38921592 */ * Stub hash: eda699f0d524fae5ae76a3a395438a16989c2af8 */
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_dom_import_simplexml, 0, 1, DOMElement, 0) ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_dom_import_simplexml, 0, 1, DOMElement, 0)
ZEND_ARG_TYPE_INFO(0, node, IS_OBJECT, 0) ZEND_ARG_TYPE_INFO(0, node, IS_OBJECT, 0)
@ -1674,6 +1674,10 @@ static const zend_function_entry class_Dom_Element_methods[] = {
ZEND_FE_END ZEND_FE_END
}; };
static const zend_function_entry class_Dom_HTMLElement_methods[] = {
ZEND_FE_END
};
static const zend_function_entry class_Dom_Attr_methods[] = { static const zend_function_entry class_Dom_Attr_methods[] = {
ZEND_RAW_FENTRY("isId", zim_DOMAttr_isId, arginfo_class_Dom_Attr_isId, ZEND_ACC_PUBLIC, NULL, NULL) ZEND_RAW_FENTRY("isId", zim_DOMAttr_isId, arginfo_class_Dom_Attr_isId, ZEND_ACC_PUBLIC, NULL, NULL)
ZEND_FE_END ZEND_FE_END
@ -3080,6 +3084,16 @@ static zend_class_entry *register_class_Dom_Element(zend_class_entry *class_entr
return class_entry; return class_entry;
} }
static zend_class_entry *register_class_Dom_HTMLElement(zend_class_entry *class_entry_Dom_Element)
{
zend_class_entry ce, *class_entry;
INIT_NS_CLASS_ENTRY(ce, "Dom", "HTMLElement", class_Dom_HTMLElement_methods);
class_entry = zend_register_internal_class_ex(&ce, class_entry_Dom_Element);
return class_entry;
}
static zend_class_entry *register_class_Dom_Attr(zend_class_entry *class_entry_Dom_Node) static zend_class_entry *register_class_Dom_Attr(zend_class_entry *class_entry_Dom_Node)
{ {
zend_class_entry ce, *class_entry; zend_class_entry ce, *class_entry;
@ -3445,15 +3459,15 @@ static zend_class_entry *register_class_Dom_Document(zend_class_entry *class_ent
zval property_body_default_value; zval property_body_default_value;
ZVAL_UNDEF(&property_body_default_value); ZVAL_UNDEF(&property_body_default_value);
zend_string *property_body_name = zend_string_init("body", sizeof("body") - 1, 1); zend_string *property_body_name = zend_string_init("body", sizeof("body") - 1, 1);
zend_string *property_body_class_Dom_Element = zend_string_init("Dom\\Element", sizeof("Dom\\Element")-1, 1); zend_string *property_body_class_Dom_HTMLElement = zend_string_init("Dom\\HTMLElement", sizeof("Dom\\HTMLElement")-1, 1);
zend_declare_typed_property(class_entry, property_body_name, &property_body_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_body_class_Dom_Element, 0, MAY_BE_NULL)); zend_declare_typed_property(class_entry, property_body_name, &property_body_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_body_class_Dom_HTMLElement, 0, MAY_BE_NULL));
zend_string_release(property_body_name); zend_string_release(property_body_name);
zval property_head_default_value; zval property_head_default_value;
ZVAL_UNDEF(&property_head_default_value); ZVAL_UNDEF(&property_head_default_value);
zend_string *property_head_name = zend_string_init("head", sizeof("head") - 1, 1); zend_string *property_head_name = zend_string_init("head", sizeof("head") - 1, 1);
zend_string *property_head_class_Dom_Element = zend_string_init("Dom\\Element", sizeof("Dom\\Element")-1, 1); zend_string *property_head_class_Dom_HTMLElement = zend_string_init("Dom\\HTMLElement", sizeof("Dom\\HTMLElement")-1, 1);
zend_declare_typed_property(class_entry, property_head_name, &property_head_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_head_class_Dom_Element, 0, MAY_BE_NULL)); zend_declare_typed_property(class_entry, property_head_name, &property_head_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_head_class_Dom_HTMLElement, 0, MAY_BE_NULL));
zend_string_release(property_head_name); zend_string_release(property_head_name);
zval property_title_default_value; zval property_title_default_value;

View file

@ -11,7 +11,7 @@ function testNormalReplace($cb)
var_dump($dom->body?->nodeName); var_dump($dom->body?->nodeName);
try { try {
$dom->body = $cb($dom); $dom->body = $cb($dom);
} catch (DOMException $e) { } catch (Throwable $e) {
echo $e->getMessage(), "\n"; echo $e->getMessage(), "\n";
} }
var_dump($dom->body?->nodeName); var_dump($dom->body?->nodeName);
@ -50,11 +50,11 @@ The new body must either be a body or a frameset tag
string(4) "BODY" string(4) "BODY"
--- Right element tag in wrong namespace --- --- Right element tag in wrong namespace ---
string(4) "BODY" string(4) "BODY"
The new body must either be a body or a frameset tag Cannot assign Dom\Element to property Dom\Document::$body of type ?Dom\HTMLElement
string(4) "BODY" string(4) "BODY"
--- Right element tag in no namespace --- --- Right element tag in no namespace ---
string(4) "BODY" string(4) "BODY"
The new body must either be a body or a frameset tag Cannot assign Dom\Element to property Dom\Document::$body of type ?Dom\HTMLElement
string(4) "BODY" string(4) "BODY"
--- Set body without document element --- --- Set body without document element ---
A body can only be set if there is a document element A body can only be set if there is a document element

View file

@ -5,7 +5,7 @@ dom
--FILE-- --FILE--
<?php <?php
class Custom extends Dom\Element { class Custom extends Dom\HTMLElement {
public int $test = 1; public int $test = 1;
public function reverseTagName(): string { public function reverseTagName(): string {
@ -15,7 +15,7 @@ class Custom extends Dom\Element {
} }
$dom = Dom\HTMLDocument::createFromString("<div>foo</div>", LIBXML_NOERROR); $dom = Dom\HTMLDocument::createFromString("<div>foo</div>", LIBXML_NOERROR);
$dom->registerNodeClass("Dom\\Element", "Custom"); $dom->registerNodeClass("Dom\\HTMLElement", "Custom");
var_dump($dom->getElementsByTagName('div')[0]->reverseTagName()); var_dump($dom->getElementsByTagName('div')[0]->reverseTagName());

View file

@ -5,10 +5,10 @@ dom
--FILE-- --FILE--
<?php <?php
class MyElement extends Dom\Element {} class MyElement extends Dom\HTMLElement {}
$dom = Dom\HTMLDocument::createFromString("<p>foo</p>", LIBXML_NOERROR); $dom = Dom\HTMLDocument::createFromString("<p>foo</p>", LIBXML_NOERROR);
$dom->registerNodeClass("Dom\\Element", "MyElement"); $dom->registerNodeClass("Dom\\HTMLElement", "MyElement");
// Destroy reference to the DOM // Destroy reference to the DOM
$child = $dom->documentElement; $child = $dom->documentElement;

View file

@ -5,10 +5,10 @@ dom
--FILE-- --FILE--
<?php <?php
class MyElement extends Dom\Element {} class MyElement extends Dom\HTMLElement {}
$dom = Dom\HTMLDocument::createFromString("<p>foo</p>", LIBXML_NOERROR); $dom = Dom\HTMLDocument::createFromString("<p>foo</p>", LIBXML_NOERROR);
$dom->registerNodeClass("Dom\\Element", "MyElement"); $dom->registerNodeClass("Dom\\HTMLElement", "MyElement");
$child = $dom->documentElement->appendChild($dom->createElement('html')); $child = $dom->documentElement->appendChild($dom->createElement('html'));
// Destroy reference to the DOM // Destroy reference to the DOM

View file

@ -14,5 +14,5 @@ try {
echo $dom->saveXml(); echo $dom->saveXml();
?> ?>
--EXPECT-- --EXPECT--
Cannot modify readonly property Dom\Element::$prefix Cannot modify readonly property Dom\HTMLElement::$prefix
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>