diff --git a/NEWS b/NEWS index 1e327fab6e04a..5191a9fd554cd 100644 --- a/NEWS +++ b/NEWS @@ -55,6 +55,7 @@ PHP NEWS . Implemented opt-in ext/dom spec compliance RFC. (nielsdos) . Fixed bug #79701 (getElementById does not correctly work with duplicate definitions). (nielsdos) + . Implemented "New ext-dom features in PHP 8.4" RFC. (nielsdos) - Fileinfo: . Update to libmagic 5.45. (nielsdos) diff --git a/UPGRADING b/UPGRADING index 72eed3e71ac19..07cc55ce12dd8 100644 --- a/UPGRADING +++ b/UPGRADING @@ -639,6 +639,8 @@ PHP 8.4 UPGRADE NOTES equivalents to the old DOM classes in the global namespaces. The new classes follow the DOM living spec. RFC: https://wiki.php.net/rfc/opt_in_dom_spec_compliance + . Implemented "New ext-dom features in PHP 8.4" RFC. + RFC: https://wiki.php.net/rfc/dom_additions_84 ======================================== 8. Removed Extensions and SAPIs diff --git a/ext/dom/config.m4 b/ext/dom/config.m4 index 4dcde6105a583..0db013b8689d1 100644 --- a/ext/dom/config.m4 +++ b/ext/dom/config.m4 @@ -25,7 +25,7 @@ if test "$PHP_DOM" != "no"; then $LEXBOR_DIR/selectors/selectors.c \ $LEXBOR_DIR/ns/ns.c \ $LEXBOR_DIR/tag/tag.c" - PHP_NEW_EXTENSION(dom, [php_dom.c attr.c document.c \ + PHP_NEW_EXTENSION(dom, [php_dom.c attr.c document.c infra.c \ xml_document.c html_document.c xml_serializer.c html5_serializer.c html5_parser.c namespace_compat.c \ domexception.c parentnode.c \ processinginstruction.c cdatasection.c \ diff --git a/ext/dom/config.w32 b/ext/dom/config.w32 index 1a5d33bf7ca4f..02a7e0a9409d1 100644 --- a/ext/dom/config.w32 +++ b/ext/dom/config.w32 @@ -7,7 +7,7 @@ if (PHP_DOM == "yes") { ADD_EXTENSION_DEP('dom', 'libxml') && CHECK_HEADER_ADD_INCLUDE("libxml/parser.h", "CFLAGS_DOM", PHP_PHP_BUILD + "\\include\\libxml2") ) { - EXTENSION("dom", "php_dom.c attr.c document.c \ + EXTENSION("dom", "php_dom.c attr.c document.c infra.c \ xml_document.c html_document.c xml_serializer.c html5_serializer.c html5_parser.c namespace_compat.c \ domexception.c parentnode.c processinginstruction.c \ cdatasection.c documentfragment.c domimplementation.c element.c \ diff --git a/ext/dom/dom_ce.h b/ext/dom/dom_ce.h index 4dee34305331f..13e58957df313 100644 --- a/ext/dom/dom_ce.h +++ b/ext/dom/dom_ce.h @@ -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_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_modern_text_class_entry; extern PHP_DOM_EXPORT zend_class_entry *dom_comment_class_entry; diff --git a/ext/dom/dom_properties.h b/ext/dom/dom_properties.h index fc8e530b01590..a9b6df87594fe 100644 --- a/ext/dom/dom_properties.h +++ b/ext/dom/dom_properties.h @@ -62,6 +62,11 @@ zend_result dom_document_substitue_entities_write(dom_object *obj, zval *newval) /* html5 document properties */ zend_result dom_html_document_encoding_write(dom_object *obj, zval *retval); +zend_result dom_html_document_body_read(dom_object *obj, zval *retval); +zend_result dom_html_document_body_write(dom_object *obj, zval *newval); +zend_result dom_html_document_head_read(dom_object *obj, zval *retval); +zend_result dom_html_document_title_read(dom_object *obj, zval *retval); +zend_result dom_html_document_title_write(dom_object *obj, zval *newval); /* documenttype properties */ zend_result dom_documenttype_name_read(dom_object *obj, zval *retval); diff --git a/ext/dom/html_document.c b/ext/dom/html_document.c index 9fef8c25a8af6..7d3670208887b 100644 --- a/ext/dom/html_document.c +++ b/ext/dom/html_document.c @@ -21,6 +21,7 @@ #include "php.h" #if defined(HAVE_LIBXML) && defined(HAVE_DOM) #include "php_dom.h" +#include "infra.h" #include "html5_parser.h" #include "html5_serializer.h" #include "namespace_compat.h" @@ -1358,4 +1359,285 @@ zend_result dom_html_document_encoding_write(dom_object *obj, zval *newval) return SUCCESS; } +static xmlNodePtr dom_html_document_element_read_raw(const xmlDoc *docp, bool (*accept)(const xmlChar *)) +{ + const xmlNode *root = xmlDocGetRootElement(docp); + if (root == NULL || !(php_dom_ns_is_fast(root, php_dom_ns_is_html_magic_token) && xmlStrEqual(root->name, BAD_CAST "html"))) { + return NULL; + } + + xmlNodePtr cur = root->children; + while (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE && php_dom_ns_is_fast(cur, php_dom_ns_is_html_magic_token) && accept(cur->name)) { + return cur; + } + cur = cur->next; + } + + return NULL; +} + +zend_result dom_html_document_element_read_helper(dom_object *obj, zval *retval, bool (*accept)(const xmlChar *)) +{ + DOM_PROP_NODE(const xmlDoc *, docp, obj); + + const xmlNode *element = dom_html_document_element_read_raw(docp, accept); + if (element == NULL) { + ZVAL_NULL(retval); + } else { + php_dom_create_object((xmlNodePtr) element, retval, obj); + } + + return SUCCESS; +} + +static bool dom_accept_body_name(const xmlChar *name) +{ + return xmlStrEqual(name, BAD_CAST "body") || xmlStrEqual(name, BAD_CAST "frameset"); +} + +static bool dom_accept_head_name(const xmlChar *name) +{ + return xmlStrEqual(name, BAD_CAST "head"); +} + +/* https://html.spec.whatwg.org/#dom-document-body */ +zend_result dom_html_document_body_read(dom_object *obj, zval *retval) +{ + return dom_html_document_element_read_helper(obj, retval, dom_accept_body_name); +} + +/* https://html.spec.whatwg.org/#dom-document-head */ +zend_result dom_html_document_head_read(dom_object *obj, zval *retval) +{ + return dom_html_document_element_read_helper(obj, retval, dom_accept_head_name); +} + +/* https://html.spec.whatwg.org/#dom-document-body */ +zend_result dom_html_document_body_write(dom_object *obj, zval *newval) +{ + DOM_PROP_NODE(xmlDocPtr, docp, obj); + + /* 1. If the new value is not a body or frameset element, then throw a "HierarchyRequestError" DOMException. */ + if (Z_TYPE_P(newval) != IS_NULL) { + dom_object *newval_intern = Z_DOMOBJ_P(newval); + if (newval_intern->ptr != NULL) { + xmlNodePtr newval_node = ((php_libxml_node_ptr *) newval_intern->ptr)->node; + /* 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. */ + const xmlNode *current_body_element = dom_html_document_element_read_raw(docp, dom_accept_body_name); + if (current_body_element == newval_node) { + return SUCCESS; + } + + /* 3. If the body element is not null, then replace the body element with the new value within the body element's parent and return. */ + if (current_body_element != NULL) { + php_dom_adopt_node(newval_node, obj, docp); + xmlNodePtr old = xmlReplaceNode((xmlNodePtr) current_body_element, newval_node); + if (old != NULL && old->_private == NULL) { + php_libxml_node_free_resource(old); + } + return SUCCESS; + } + + /* 4. If there is no document element, throw a "HierarchyRequestError" DOMException. */ + xmlNodePtr root = xmlDocGetRootElement(docp); + if (root == NULL) { + php_dom_throw_error_with_message(HIERARCHY_REQUEST_ERR, "A body can only be set if there is a document element", true); + return FAILURE; + } + + /* 5. Append the new value to the document element. */ + php_dom_adopt_node(newval_node, obj, docp); + xmlAddChild(root, newval_node); + return SUCCESS; + } + } + } + + php_dom_throw_error_with_message(HIERARCHY_REQUEST_ERR, "The new body must either be a body or a frameset tag", true); + return FAILURE; +} + +/* https://dom.spec.whatwg.org/#concept-child-text-content */ +static zend_string *dom_get_child_text_content(const xmlNode *node) +{ + smart_str content = {0}; + + const xmlNode *text = node->children; + while (text != NULL) { + if (text->type == XML_TEXT_NODE || text->type == XML_CDATA_SECTION_NODE) { + smart_str_appends(&content, (const char *) text->content); + } + text = text->next; + } + + return smart_str_extract(&content); +} + +/* https://html.spec.whatwg.org/#the-title-element-2 */ +static xmlNodePtr dom_get_title_element(const xmlDoc *doc) +{ + xmlNodePtr node = doc->children; + + while (node != NULL) { + if (node->type == XML_ELEMENT_NODE) { + if (php_dom_ns_is_fast(node, php_dom_ns_is_html_magic_token) && xmlStrEqual(node->name, BAD_CAST "title")) { + break; + } + } + + node = php_dom_next_in_tree_order(node, NULL); + } + + return node; +} + +/* The subtle difference is that this is about the direct title descendant of the svg element, + * whereas the html variant of this function is about the first in-tree title element. */ +static xmlNodePtr dom_get_svg_title_element(xmlNodePtr svg) +{ + xmlNodePtr cur = svg->children; + + while (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE + && php_dom_ns_is_fast(cur, php_dom_ns_is_svg_magic_token) && xmlStrEqual(cur->name, BAD_CAST "title")) { + break; + } + cur = cur->next; + } + + return cur; +} + +/* https://html.spec.whatwg.org/#document.title */ +zend_result dom_html_document_title_read(dom_object *obj, zval *retval) +{ + DOM_PROP_NODE(const xmlDoc *, docp, obj); + xmlNodePtr root = xmlDocGetRootElement(docp); + + if (root == NULL) { + ZVAL_EMPTY_STRING(retval); + return SUCCESS; + } + + zend_string *value = zend_empty_string; + + /* 1. If the document element is an SVG svg element, + * then let value be the child text content of the first SVG title element that is a child of the document element. */ + if (php_dom_ns_is_fast(root, php_dom_ns_is_svg_magic_token) && xmlStrEqual(root->name, BAD_CAST "svg")) { + const xmlNode *title = dom_get_svg_title_element(root); + if (title != NULL) { + value = dom_get_child_text_content(title); + } + } else { + /* 2. Otherwise, let value be the child text content of the title element, + * or the empty string if the title element is null. */ + const xmlNode *title = dom_get_title_element(docp); + if (title != NULL) { + value = dom_get_child_text_content(title); + } + } + + /* 3. Strip and collapse ASCII whitespace in value. */ + value = dom_strip_and_collapse_ascii_whitespace(value); + + /* 4. Return value. */ + ZVAL_STR(retval, value); + + return SUCCESS; +} + +static void dom_string_replace_all(xmlDocPtr docp, xmlNodePtr element, zval *zv) +{ + dom_remove_all_children(element); + xmlNode *text = xmlNewDocText(docp, BAD_CAST Z_STRVAL_P(zv)); + xmlAddChild(element, text); +} + +/* https://html.spec.whatwg.org/#document.title */ +zend_result dom_html_document_title_write(dom_object *obj, zval *newval) +{ + DOM_PROP_NODE(xmlDocPtr, docp, obj); + xmlNodePtr root = xmlDocGetRootElement(docp); + + if (root == NULL) { + return SUCCESS; + } + + /* If the document element is an SVG svg element */ + if (php_dom_ns_is_fast(root, php_dom_ns_is_svg_magic_token) && xmlStrEqual(root->name, BAD_CAST "svg")) { + /* 1. If there is an SVG title element that is a child of the document element, let element be the first such element. */ + xmlNodePtr element = dom_get_svg_title_element(root); + + /* 2. Otherwise: */ + if (element == NULL) { + /* 2.1. Let element be the result of creating an element given the document element's node document, + * title, and the SVG namespace. */ + + /* Annoyingly, we must create it in the svg namespace _without_ prefix... */ + xmlNsPtr ns = root->ns; + if (ns->prefix != NULL) { + /* Slow path... */ + php_dom_libxml_ns_mapper *ns_mapper = php_dom_get_ns_mapper(obj); + zend_string *href = ZSTR_INIT_LITERAL(DOM_SVG_NS_URI, false); + ns = php_dom_libxml_ns_mapper_get_ns(ns_mapper, zend_empty_string, href); + zend_string_release_ex(href, false); + } + + element = xmlNewDocNode(docp, ns, BAD_CAST "title", NULL); + if (UNEXPECTED(element == NULL)) { + php_dom_throw_error(INVALID_STATE_ERR, true); + return FAILURE; + } + + /* 2.2. Insert element as the first child of the document element. */ + if (root->children == NULL) { + root->last = element; + } else { + element->next = root->children; + root->children->prev = element; + } + root->children = element; + element->parent = root; + } + + /* 3. String replace all with the given value within element. */ + dom_string_replace_all(docp, element, newval); + } + /* If the document element is in the HTML namespace */ + else if (php_dom_ns_is_fast(root, php_dom_ns_is_html_magic_token)) { + /* 1. If the title element is null and the head element is null, then return. */ + xmlNodePtr title = dom_get_title_element(docp); + xmlNodePtr head = dom_html_document_element_read_raw(docp, dom_accept_head_name); + if (title == NULL && head == NULL) { + return SUCCESS; + } + + /* 2. If the title element is non-null, let element be the title element. */ + xmlNodePtr element = title; + + /* 3. Otherwise: */ + if (element == NULL) { + /* 3.1. Let element be the result of creating an element given the document element's node document, title, + * and the HTML namespace. */ + php_dom_libxml_ns_mapper *ns_mapper = php_dom_get_ns_mapper(obj); + element = xmlNewDocNode(docp, php_dom_libxml_ns_mapper_ensure_html_ns(ns_mapper), BAD_CAST "title", NULL); + if (UNEXPECTED(element == NULL)) { + php_dom_throw_error(INVALID_STATE_ERR, true); + return FAILURE; + } + + /* 3.2. Append element to the head element. */ + xmlAddChild(head, element); + } + + /* 4. String replace all with the given value within element. */ + dom_string_replace_all(docp, element, newval); + } + + return SUCCESS; +} + #endif /* HAVE_LIBXML && HAVE_DOM */ diff --git a/ext/dom/infra.c b/ext/dom/infra.c new file mode 100644 index 0000000000000..8fa42453c7519 --- /dev/null +++ b/ext/dom/infra.c @@ -0,0 +1,77 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Niels Dossche | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#if defined(HAVE_LIBXML) && defined(HAVE_DOM) +#include "infra.h" + +/* https://infra.spec.whatwg.org/#ascii-whitespace */ +const char *ascii_whitespace = "\x09\x0A\x0C\x0D\x20"; + +/* https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace */ +zend_string *dom_strip_and_collapse_ascii_whitespace(zend_string *input) +{ + if (input == zend_empty_string) { + return input; + } + + ZEND_ASSERT(!ZSTR_IS_INTERNED(input)); + ZEND_ASSERT(GC_REFCOUNT(input) == 1); + + char *write_ptr = ZSTR_VAL(input); + + const char *start = ZSTR_VAL(input); + const char *current = start; + const char *end = current + ZSTR_LEN(input); + + current += strspn(current, ascii_whitespace); + + while (current < end) { + /* Copy non-whitespace */ + size_t non_whitespace_len = strcspn(current, ascii_whitespace); + /* If the pointers are equal, we still haven't encountered collapsable or strippable whitespace. */ + if (write_ptr != current) { + memmove(write_ptr, current, non_whitespace_len); + } + current += non_whitespace_len; + write_ptr += non_whitespace_len; + + /* Skip whitespace */ + current += strspn(current, ascii_whitespace); + if (current < end) { + /* Only make a space when we're not yet at the end of the input, because that means more non-whitespace + * input is to come. */ + *write_ptr++ = ' '; + } + } + + *write_ptr = '\0'; + + size_t len = write_ptr - start; + if (len != ZSTR_LEN(input)) { + return zend_string_truncate(input, len, false); + } else { + /* Forget the hash value since we may have transformed non-space-whitespace into spaces. */ + zend_string_forget_hash_val(input); + return input; + } +} + +#endif /* HAVE_LIBXML && HAVE_DOM */ diff --git a/ext/dom/infra.h b/ext/dom/infra.h new file mode 100644 index 0000000000000..d84ad5a2a0efa --- /dev/null +++ b/ext/dom/infra.h @@ -0,0 +1,26 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Niels Dossche | + +----------------------------------------------------------------------+ +*/ + +#ifndef INFRA_H +#define INFRA_H + +#include "zend_string.h" + +extern const char *ascii_whitespace; + +zend_string *dom_strip_and_collapse_ascii_whitespace(zend_string *input); + +#endif diff --git a/ext/dom/internal_helpers.h b/ext/dom/internal_helpers.h index a19367dd47770..b74a735ad2eeb 100644 --- a/ext/dom/internal_helpers.h +++ b/ext/dom/internal_helpers.h @@ -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(documenttype) -DOM_DEF_GET_CE_FUNC(element) DOM_DEF_GET_CE_FUNC(attr) DOM_DEF_GET_CE_FUNC(entity) DOM_DEF_GET_CE_FUNC(entityreference) diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index 2d21a891ca52a..83dc12c6428d6 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -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_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_modern_text_class_entry; PHP_DOM_EXPORT zend_class_entry *dom_comment_class_entry; @@ -851,6 +852,9 @@ PHP_MINIT_FUNCTION(dom) DOM_REGISTER_PROP_HANDLER(&dom_abstract_base_document_prop_handlers, "firstElementChild", dom_parent_node_first_element_child_read, NULL); DOM_REGISTER_PROP_HANDLER(&dom_abstract_base_document_prop_handlers, "lastElementChild", dom_parent_node_last_element_child_read, NULL); DOM_REGISTER_PROP_HANDLER(&dom_abstract_base_document_prop_handlers, "childElementCount", dom_parent_node_child_element_count, NULL); + DOM_REGISTER_PROP_HANDLER(&dom_abstract_base_document_prop_handlers, "body", dom_html_document_body_read, dom_html_document_body_write); + DOM_REGISTER_PROP_HANDLER(&dom_abstract_base_document_prop_handlers, "head", dom_html_document_head_read, NULL); + DOM_REGISTER_PROP_HANDLER(&dom_abstract_base_document_prop_handlers, "title", dom_html_document_title_read, dom_html_document_title_write); zend_hash_merge(&dom_abstract_base_document_prop_handlers, &dom_modern_node_prop_handlers, NULL, false); /* No need to register in &classes because this is an abstract class handler. */ @@ -1039,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); 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->create_object = dom_objects_new; dom_text_class_entry->default_object_handlers = &dom_object_handlers; @@ -1538,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_EXPORT bool php_dom_create_object(xmlNodePtr obj, zval *return_value, dom_object *domobj) { @@ -1569,7 +1591,7 @@ PHP_DOM_EXPORT bool php_dom_create_object(xmlNodePtr obj, zval *return_value, do } case XML_ELEMENT_NODE: { - ce = dom_get_element_ce(modern); + ce = dom_get_element_ce(obj, modern); break; } case XML_ATTRIBUTE_NODE: diff --git a/ext/dom/php_dom.stub.php b/ext/dom/php_dom.stub.php index 50fced8c46691..1f6f2bb8bc876 100644 --- a/ext/dom/php_dom.stub.php +++ b/ext/dom/php_dom.stub.php @@ -1374,6 +1374,10 @@ public function prepend(Node|string ...$nodes): void {} public function replaceChildren(Node|string ...$nodes): void {} } + class HTMLElement extends Element + { + } + class Attr extends Node { /** @readonly */ @@ -1580,6 +1584,11 @@ public function prepend(Node|string ...$nodes): void {} public function replaceChildren(Node|string ...$nodes): void {} public function importLegacyNode(\DOMNode $node, bool $deep = false): Node {} + + public ?HTMLElement $body; + /** @readonly */ + public ?HTMLElement $head; + public string $title; } final class HTMLDocument extends Document diff --git a/ext/dom/php_dom_arginfo.h b/ext/dom/php_dom_arginfo.h index a9a61a4df79cb..dae80f6fe3cfd 100644 --- a/ext/dom/php_dom_arginfo.h +++ b/ext/dom/php_dom_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: c93643bad9675fddf31ca52f82f843218f208a5d */ + * Stub hash: eda699f0d524fae5ae76a3a395438a16989c2af8 */ 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) @@ -1674,6 +1674,10 @@ static const zend_function_entry class_Dom_Element_methods[] = { ZEND_FE_END }; +static const zend_function_entry class_Dom_HTMLElement_methods[] = { + ZEND_FE_END +}; + 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_FE_END @@ -3080,6 +3084,16 @@ static zend_class_entry *register_class_Dom_Element(zend_class_entry *class_entr 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) { zend_class_entry ce, *class_entry; @@ -3442,6 +3456,26 @@ static zend_class_entry *register_class_Dom_Document(zend_class_entry *class_ent zend_declare_typed_property(class_entry, property_childElementCount_name, &property_childElementCount_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(property_childElementCount_name); + zval 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_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_HTMLElement, 0, MAY_BE_NULL)); + zend_string_release(property_body_name); + + zval 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_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_HTMLElement, 0, MAY_BE_NULL)); + zend_string_release(property_head_name); + + zval property_title_default_value; + ZVAL_UNDEF(&property_title_default_value); + zend_string *property_title_name = zend_string_init("title", sizeof("title") - 1, 1); + zend_declare_typed_property(class_entry, property_title_name, &property_title_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + zend_string_release(property_title_name); + return class_entry; } diff --git a/ext/dom/tests/modern/common/Document_title_getter.phpt b/ext/dom/tests/modern/common/Document_title_getter.phpt new file mode 100644 index 0000000000000..eb4f4b7cdb5fd --- /dev/null +++ b/ext/dom/tests/modern/common/Document_title_getter.phpt @@ -0,0 +1,79 @@ +--TEST-- +Dom\Document::$title getter +--EXTENSIONS-- +dom +--FILE-- +A normal title without collapsable or strippable whitespace"); +var_dump($dom->title); + +$dom = Dom\XMLDocument::createFromString(" only ws at front"); +var_dump($dom->title); + +$dom = Dom\XMLDocument::createFromString("only ws at back "); +var_dump($dom->title); + +$dom = Dom\XMLDocument::createFromString("
first
second
"); +var_dump($dom->title); + +$dom = Dom\XMLDocument::createFromString("title"); +var_dump($dom->title); + +$dom = Dom\XMLDocument::createFromString(" abc def ghi "); +var_dump($dom->title); + +$dom = Dom\XMLDocument::createFromString(""); +var_dump($dom->title); + +$dom = Dom\XMLDocument::createFromString(""); +var_dump($dom->title); + +$dom = Dom\XMLDocument::createFromString(" \t\r\n "); +var_dump($dom->title); + +$dom = Dom\XMLDocument::createFromString(" \tx<?y y?><![CDATA[z]]>\n "); +var_dump($dom->title); + +$dom = Dom\XMLDocument::createFromString("<div><!-- comment -->x</div>y<p>z</p>w"); +var_dump($dom->title); + +$dom = Dom\XMLDocument::createFromString("title\nhere"); +var_dump($dom->title); + +echo "=== SVG namespaced root ===\n"; + +$dom = Dom\XMLDocument::createFromString("title"); +var_dump($dom->title); + +$dom = Dom\XMLDocument::createFromString("title"); +var_dump($dom->title); + +$dom = Dom\XMLDocument::createFromString("titlehi"); +var_dump($dom->title); + +$dom = Dom\XMLDocument::createFromString(""); +var_dump($dom->title); + +?> +--EXPECT-- +=== HTML namespaced root === +string(59) "A normal title without collapsable or strippable whitespace" +string(16) "only ws at front" +string(15) "only ws at back" +string(5) "first" +string(5) "title" +string(11) "abc def ghi" +string(0) "" +string(0) "" +string(0) "" +string(2) "xz" +string(2) "yw" +string(10) "title here" +=== SVG namespaced root === +string(5) "title" +string(5) "title" +string(5) "title" +string(0) "" diff --git a/ext/dom/tests/modern/common/Document_title_setter.phpt b/ext/dom/tests/modern/common/Document_title_setter.phpt new file mode 100644 index 0000000000000..9cf91b0339b81 --- /dev/null +++ b/ext/dom/tests/modern/common/Document_title_setter.phpt @@ -0,0 +1,105 @@ +--TEST-- +Dom\Document::$title setter +--EXTENSIONS-- +dom +--FILE-- +'); +$dom->title = "hello & world"; +echo $dom->saveXML(), "\n"; + +$dom = Dom\XMLDocument::createFromString(''); +$dom->title = "hello & world"; +echo $dom->saveXML(), "\n"; +$dom->title = ""; +echo $dom->saveXML(), "\n"; +$dom->title = "test"; +echo $dom->saveXML(), "\n"; + +$dom = Dom\XMLDocument::createFromString(''); +$dom->title = "test"; +echo $dom->saveXML(), "\n"; +var_dump($dom->documentElement->firstElementChild->prefix, $dom->documentElement->firstElementChild->namespaceURI); + +$dom = Dom\XMLDocument::createFromString('first node
'); +$dom->title = "test"; +echo $dom->saveXML(), "\n"; +$dom->documentElement->firstElementChild->remove(); +$dom->title = "test2"; +echo $dom->saveXML(), "\n"; + +echo "\n=== HTML namespaced test ===\n\n"; + +$dom = Dom\XMLDocument::createFromString(''); +$dom->title = "test"; +echo $dom->saveXML(), "\n"; + +$dom = Dom\XMLDocument::createFromString(''); +$dom->title = "test"; +echo $dom->saveXML(), "\n"; + +$dom = Dom\XMLDocument::createFromString(''); +$dom->title = "test"; +echo $dom->saveXML(), "\n"; + +$dom = Dom\XMLDocument::createFromString(''); +$dom->title = "test"; +echo $dom->saveXML(), "\n"; + +$dom = Dom\XMLDocument::createFromString('foo<div/>'); +$dom->title = "test"; +echo $dom->saveXML(), "\n"; + +echo "\n=== neither namespaced test ===\n\n"; + +$dom = Dom\XMLDocument::createEmpty(); +$dom->title = ""; +echo $dom->saveXML(), "\n"; + +$dom = Dom\XMLDocument::createFromString(''); +$dom->title = "test"; +echo $dom->saveXML(), "\n"; + +?> +--EXPECT-- +=== SVG namespaced test === + + + + +hello &amp; world + + + +test + +test +NULL +string(26) "http://www.w3.org/2000/svg" + +testfirst node
+ +test2first node
+ +=== HTML namespaced test === + + + + + + +test + +test + +test + +=== neither namespaced test === + + + + + diff --git a/ext/dom/tests/modern/html/interactions/Document_body_getter.phpt b/ext/dom/tests/modern/html/interactions/Document_body_getter.phpt new file mode 100644 index 0000000000000..79201ab3cf3b9 --- /dev/null +++ b/ext/dom/tests/modern/html/interactions/Document_body_getter.phpt @@ -0,0 +1,98 @@ +--TEST-- +Test Dom\Document::$body getter +--EXTENSIONS-- +dom +--FILE-- +foo

", LIBXML_NOERROR); +var_dump($dom->body?->nodeName); + +echo "--- After body removal ---\n"; + +$dom->body->remove(); +var_dump($dom->body?->nodeName); + +echo "--- body in no namespace ---\n"; + +$tmp = $dom->documentElement->appendChild($dom->createElementNS("", "body")); +var_dump($dom->body?->nodeName); +$tmp->remove(); + +echo "--- frameset in no namespace ---\n"; + +$tmp = $dom->documentElement->appendChild($dom->createElementNS("", "frameset")); +var_dump($dom->body?->nodeName); +$tmp->remove(); + +echo "--- body in right namespace ---\n"; + +$tmp = $dom->documentElement->appendChild($dom->createElementNS("http://www.w3.org/1999/xhtml", "body")); +var_dump($dom->body?->nodeName); +$tmp->remove(); + +echo "--- frameset in right namespace ---\n"; + +$tmp = $dom->documentElement->appendChild($dom->createElementNS("http://www.w3.org/1999/xhtml", "frameset")); +var_dump($dom->body?->nodeName); +$tmp->remove(); + +echo "--- prefixed body in right namespace ---\n"; + +$tmp = $dom->documentElement->appendChild($dom->createElementNS("http://www.w3.org/1999/xhtml", "prefix:body")); +var_dump($dom->body?->nodeName); +$tmp->remove(); + +echo "--- prefixed frameset in right namespace ---\n"; + +$tmp = $dom->documentElement->appendChild($dom->createElementNS("http://www.w3.org/1999/xhtml", "prefix:frameset")); +var_dump($dom->body?->nodeName); +$tmp->remove(); + +echo "--- multiple body-like elements in right namespace ---\n"; + +$tmp1 = $dom->documentElement->appendChild($dom->createElementNS("http://www.w3.org/1999/xhtml", "prefix1:body")); +var_dump($dom->body?->nodeName); +$tmp2 = $dom->documentElement->appendChild($dom->createElementNS("http://www.w3.org/1999/xhtml", "prefix2:frameset")); +var_dump($dom->body?->nodeName); +$tmp1->remove(); +var_dump($dom->body?->nodeName); +$tmp2->remove(); +var_dump($dom->body?->nodeName); + +echo "--- html element in no namespace ---\n"; + +$dom = Dom\XMLDocument::createFromString(<< + + +XML); +var_dump($dom->body); + +?> +--EXPECT-- +--- From parsing --- +string(4) "BODY" +--- After body removal --- +NULL +--- body in no namespace --- +NULL +--- frameset in no namespace --- +NULL +--- body in right namespace --- +string(4) "BODY" +--- frameset in right namespace --- +string(8) "FRAMESET" +--- prefixed body in right namespace --- +string(11) "PREFIX:BODY" +--- prefixed frameset in right namespace --- +string(15) "PREFIX:FRAMESET" +--- multiple body-like elements in right namespace --- +string(12) "PREFIX1:BODY" +string(12) "PREFIX1:BODY" +string(16) "PREFIX2:FRAMESET" +NULL +--- html element in no namespace --- +NULL diff --git a/ext/dom/tests/modern/html/interactions/Document_body_setter.phpt b/ext/dom/tests/modern/html/interactions/Document_body_setter.phpt new file mode 100644 index 0000000000000..87cbb9b9c9e6e --- /dev/null +++ b/ext/dom/tests/modern/html/interactions/Document_body_setter.phpt @@ -0,0 +1,48 @@ +--TEST-- +Test DOM\Document::$body setter +--EXTENSIONS-- +dom +--FILE-- +foo

', LIBXML_NOERROR); +$dom->body = $dom->body; +var_dump($dom->body?->nodeName); + +echo "--- Add body when there is no body yet ---\n"; +$dom = DOM\HTMLDocument::createFromString('

foo

', LIBXML_NOERROR); +$dom->body->remove(); +$dom->body = $dom->createElementNS("http://www.w3.org/1999/xhtml", "prefix:body"); +var_dump($dom->body?->nodeName); + +echo "--- Replace old body with new body ---\n"; +$dom = DOM\HTMLDocument::createFromString('

foo

', LIBXML_NOERROR); +$dom->body = $dom->createElementNS("http://www.w3.org/1999/xhtml", "prefix:body"); +var_dump($dom->body?->nodeName); + +echo "--- Replace old body with new body, while still having a reference to the old body ---\n"; +$dom = DOM\HTMLDocument::createFromString('

foo

', LIBXML_NOERROR); +$old = $dom->body; +$dom->body = $dom->createElementNS("http://www.w3.org/1999/xhtml", "prefix:body"); +var_dump($dom->body?->nodeName); +var_dump($old->nodeName); + +echo "--- Special note from the DOM spec ---\n"; +$dom = DOM\XMLDocument::createFromString(''); +$dom->body = $dom->createElementNS("http://www.w3.org/1999/xhtml", "body"); +var_dump($dom->body?->nodeName); + +?> +--EXPECT-- +--- Replace body with itself --- +string(4) "BODY" +--- Add body when there is no body yet --- +string(11) "PREFIX:BODY" +--- Replace old body with new body --- +string(11) "PREFIX:BODY" +--- Replace old body with new body, while still having a reference to the old body --- +string(11) "PREFIX:BODY" +string(4) "BODY" +--- Special note from the DOM spec --- +NULL diff --git a/ext/dom/tests/modern/html/interactions/Document_body_setter_errors.phpt b/ext/dom/tests/modern/html/interactions/Document_body_setter_errors.phpt new file mode 100644 index 0000000000000..1f934fcff890d --- /dev/null +++ b/ext/dom/tests/modern/html/interactions/Document_body_setter_errors.phpt @@ -0,0 +1,61 @@ +--TEST-- +Test DOM\Document::$body setter errors +--EXTENSIONS-- +dom +--FILE-- +foo

', LIBXML_NOERROR); + var_dump($dom->body?->nodeName); + try { + $dom->body = $cb($dom); + } catch (Throwable $e) { + echo $e->getMessage(), "\n"; + } + var_dump($dom->body?->nodeName); +} + +echo "--- Set body to NULL ---\n"; +testNormalReplace(fn ($dom) => NULL); + +echo "--- Wrong element tag in right namespace ---\n"; +testNormalReplace(fn ($dom) => $dom->createElementNS("http://www.w3.org/1999/xhtml", "foo")); + +echo "--- Right element tag in wrong namespace ---\n"; +testNormalReplace(fn ($dom) => $dom->createElementNS("urn:a", "body")); + +echo "--- Right element tag in no namespace ---\n"; +testNormalReplace(fn ($dom) => $dom->createElementNS("", "frameset")); + +echo "--- Set body without document element ---\n"; +$dom = DOM\XMLDocument::createEmpty(); +try { + $dom->body = $dom->createElementNS("http://www.w3.org/1999/xhtml", "body"); +} catch (DOMException $e) { + echo $e->getMessage(), "\n"; +} +var_dump($dom->body?->nodeName); + +?> +--EXPECT-- +--- Set body to NULL --- +string(4) "BODY" +The new body must either be a body or a frameset tag +string(4) "BODY" +--- Wrong element tag in right namespace --- +string(4) "BODY" +The new body must either be a body or a frameset tag +string(4) "BODY" +--- Right element tag in wrong namespace --- +string(4) "BODY" +Cannot assign Dom\Element to property Dom\Document::$body of type ?Dom\HTMLElement +string(4) "BODY" +--- Right element tag in no namespace --- +string(4) "BODY" +Cannot assign Dom\Element to property Dom\Document::$body of type ?Dom\HTMLElement +string(4) "BODY" +--- Set body without document element --- +A body can only be set if there is a document element +NULL diff --git a/ext/dom/tests/modern/html/interactions/Document_head.phpt b/ext/dom/tests/modern/html/interactions/Document_head.phpt new file mode 100644 index 0000000000000..cc34945951405 --- /dev/null +++ b/ext/dom/tests/modern/html/interactions/Document_head.phpt @@ -0,0 +1,74 @@ +--TEST-- +Test Dom\Document::$head +--EXTENSIONS-- +dom +--FILE-- +foo

", LIBXML_NOERROR); +var_dump($dom->head?->nodeName); + +echo "--- After head removal ---\n"; + +$dom->head->remove(); +var_dump($dom->head?->nodeName); + +echo "--- head in no namespace ---\n"; + +$tmp = $dom->documentElement->appendChild($dom->createElementNS("", "head")); +var_dump($dom->head?->nodeName); +$tmp->remove(); + +echo "--- head in right namespace ---\n"; + +$tmp = $dom->documentElement->appendChild($dom->createElementNS("http://www.w3.org/1999/xhtml", "head")); +var_dump($dom->head?->nodeName); +$tmp->remove(); + +echo "--- prefixed head in right namespace ---\n"; + +$tmp = $dom->documentElement->appendChild($dom->createElementNS("http://www.w3.org/1999/xhtml", "prefix:head")); +var_dump($dom->head?->nodeName); +$tmp->remove(); + +echo "--- multiple head elements in right namespace ---\n"; + +$tmp1 = $dom->documentElement->appendChild($dom->createElementNS("http://www.w3.org/1999/xhtml", "prefix1:head")); +var_dump($dom->head?->nodeName); +$tmp2 = $dom->documentElement->appendChild($dom->createElementNS("http://www.w3.org/1999/xhtml", "prefix2:head")); +var_dump($dom->head?->nodeName); +$tmp1->remove(); +var_dump($dom->head?->nodeName); +$tmp2->remove(); +var_dump($dom->head?->nodeName); + +echo "--- html element in no namespace ---\n"; + +$dom = Dom\XMLDocument::createFromString(<< + + +XML); +var_dump($dom->head); + +?> +--EXPECT-- +--- From parsing --- +string(4) "HEAD" +--- After head removal --- +NULL +--- head in no namespace --- +NULL +--- head in right namespace --- +string(4) "HEAD" +--- prefixed head in right namespace --- +string(11) "PREFIX:HEAD" +--- multiple head elements in right namespace --- +string(12) "PREFIX1:HEAD" +string(12) "PREFIX1:HEAD" +string(12) "PREFIX2:HEAD" +NULL +--- html element in no namespace --- +NULL diff --git a/ext/dom/tests/modern/html/interactions/HTMLDocument_registerNodeClass_03.phpt b/ext/dom/tests/modern/html/interactions/HTMLDocument_registerNodeClass_03.phpt index 7a4d2d32797dc..6616eb5d11465 100644 --- a/ext/dom/tests/modern/html/interactions/HTMLDocument_registerNodeClass_03.phpt +++ b/ext/dom/tests/modern/html/interactions/HTMLDocument_registerNodeClass_03.phpt @@ -5,7 +5,7 @@ dom --FILE-- foo
", LIBXML_NOERROR); -$dom->registerNodeClass("Dom\\Element", "Custom"); +$dom->registerNodeClass("Dom\\HTMLElement", "Custom"); var_dump($dom->getElementsByTagName('div')[0]->reverseTagName()); diff --git a/ext/dom/tests/modern/html/interactions/HTMLDocument_should_retain_properties_and_owner_01.phpt b/ext/dom/tests/modern/html/interactions/HTMLDocument_should_retain_properties_and_owner_01.phpt index 2931aebab28f5..5051c3f9aabf6 100644 --- a/ext/dom/tests/modern/html/interactions/HTMLDocument_should_retain_properties_and_owner_01.phpt +++ b/ext/dom/tests/modern/html/interactions/HTMLDocument_should_retain_properties_and_owner_01.phpt @@ -5,10 +5,10 @@ dom --FILE-- foo

", LIBXML_NOERROR); -$dom->registerNodeClass("Dom\\Element", "MyElement"); +$dom->registerNodeClass("Dom\\HTMLElement", "MyElement"); // Destroy reference to the DOM $child = $dom->documentElement; @@ -23,7 +23,7 @@ var_dump(get_class($dom->getElementsByTagName("p")->item(0))); ?> --EXPECT-- -object(Dom\HTMLDocument)#1 (25) { +object(Dom\HTMLDocument)#1 (28) { ["implementation"]=> string(22) "(object value omitted)" ["URL"]=> @@ -46,6 +46,12 @@ object(Dom\HTMLDocument)#1 (25) { string(22) "(object value omitted)" ["childElementCount"]=> int(1) + ["body"]=> + string(22) "(object value omitted)" + ["head"]=> + string(22) "(object value omitted)" + ["title"]=> + string(0) "" ["nodeType"]=> int(13) ["nodeName"]=> diff --git a/ext/dom/tests/modern/html/interactions/HTMLDocument_should_retain_properties_and_owner_02.phpt b/ext/dom/tests/modern/html/interactions/HTMLDocument_should_retain_properties_and_owner_02.phpt index c356cf7ba9215..b160c72f0a54f 100644 --- a/ext/dom/tests/modern/html/interactions/HTMLDocument_should_retain_properties_and_owner_02.phpt +++ b/ext/dom/tests/modern/html/interactions/HTMLDocument_should_retain_properties_and_owner_02.phpt @@ -5,10 +5,10 @@ dom --FILE-- foo

", LIBXML_NOERROR); -$dom->registerNodeClass("Dom\\Element", "MyElement"); +$dom->registerNodeClass("Dom\\HTMLElement", "MyElement"); $child = $dom->documentElement->appendChild($dom->createElement('html')); // Destroy reference to the DOM @@ -23,7 +23,7 @@ var_dump(get_class($dom->getElementsByTagName("p")->item(0))); ?> --EXPECT-- -object(Dom\HTMLDocument)#1 (25) { +object(Dom\HTMLDocument)#1 (28) { ["implementation"]=> string(22) "(object value omitted)" ["URL"]=> @@ -46,6 +46,12 @@ object(Dom\HTMLDocument)#1 (25) { string(22) "(object value omitted)" ["childElementCount"]=> int(1) + ["body"]=> + string(22) "(object value omitted)" + ["head"]=> + string(22) "(object value omitted)" + ["title"]=> + string(0) "" ["nodeType"]=> int(13) ["nodeName"]=> diff --git a/ext/dom/tests/modern/spec/Document_implementation_createDocument.phpt b/ext/dom/tests/modern/spec/Document_implementation_createDocument.phpt index 5384cf6331f76..ae49a6a494c9a 100644 --- a/ext/dom/tests/modern/spec/Document_implementation_createDocument.phpt +++ b/ext/dom/tests/modern/spec/Document_implementation_createDocument.phpt @@ -37,7 +37,7 @@ echo $dom->implementation->createDocument(null, "", $dtd)->saveXml(), "\n"; ?> --EXPECT-- --- (null, "") --- -object(Dom\XMLDocument)#3 (29) { +object(Dom\XMLDocument)#3 (32) { ["xmlEncoding"]=> string(5) "UTF-8" ["xmlStandalone"]=> @@ -68,6 +68,12 @@ object(Dom\XMLDocument)#3 (29) { NULL ["childElementCount"]=> int(0) + ["body"]=> + NULL + ["head"]=> + NULL + ["title"]=> + string(0) "" ["nodeType"]=> int(9) ["nodeName"]=> diff --git a/ext/dom/tests/modern/spec/Element_prefix_readonly.phpt b/ext/dom/tests/modern/spec/Element_prefix_readonly.phpt index 7ebc3efaadc2b..78625fcb6f7d3 100644 --- a/ext/dom/tests/modern/spec/Element_prefix_readonly.phpt +++ b/ext/dom/tests/modern/spec/Element_prefix_readonly.phpt @@ -14,5 +14,5 @@ try { echo $dom->saveXml(); ?> --EXPECT-- -Cannot modify readonly property Dom\Element::$prefix +Cannot modify readonly property Dom\HTMLElement::$prefix diff --git a/ext/dom/tests/modern/xml/XMLDocument_debug.phpt b/ext/dom/tests/modern/xml/XMLDocument_debug.phpt index c9ae2afa95fdf..e2d6ebffe89cd 100644 --- a/ext/dom/tests/modern/xml/XMLDocument_debug.phpt +++ b/ext/dom/tests/modern/xml/XMLDocument_debug.phpt @@ -10,7 +10,7 @@ var_dump($dom); ?> --EXPECT-- -object(Dom\XMLDocument)#1 (29) { +object(Dom\XMLDocument)#1 (32) { ["xmlEncoding"]=> string(5) "UTF-8" ["xmlStandalone"]=> @@ -41,6 +41,12 @@ object(Dom\XMLDocument)#1 (29) { NULL ["childElementCount"]=> int(0) + ["body"]=> + NULL + ["head"]=> + NULL + ["title"]=> + string(0) "" ["nodeType"]=> int(9) ["nodeName"]=> diff --git a/ext/dom/tests/modern/xml/XMLDocument_fromEmptyDocument_02.phpt b/ext/dom/tests/modern/xml/XMLDocument_fromEmptyDocument_02.phpt index a804394bc8441..62d64a05f9b2a 100644 --- a/ext/dom/tests/modern/xml/XMLDocument_fromEmptyDocument_02.phpt +++ b/ext/dom/tests/modern/xml/XMLDocument_fromEmptyDocument_02.phpt @@ -10,7 +10,7 @@ var_dump($dom); ?> --EXPECT-- -object(Dom\XMLDocument)#1 (29) { +object(Dom\XMLDocument)#1 (32) { ["xmlEncoding"]=> string(5) "UTF-8" ["xmlStandalone"]=> @@ -41,6 +41,12 @@ object(Dom\XMLDocument)#1 (29) { NULL ["childElementCount"]=> int(0) + ["body"]=> + NULL + ["head"]=> + NULL + ["title"]=> + string(0) "" ["nodeType"]=> int(9) ["nodeName"]=> diff --git a/ext/dom/tests/modern/xml/XMLDocument_node_ownerDocument_for_XML.phpt b/ext/dom/tests/modern/xml/XMLDocument_node_ownerDocument_for_XML.phpt index 946f9495114a7..e18c43f05ae82 100644 --- a/ext/dom/tests/modern/xml/XMLDocument_node_ownerDocument_for_XML.phpt +++ b/ext/dom/tests/modern/xml/XMLDocument_node_ownerDocument_for_XML.phpt @@ -13,7 +13,7 @@ var_dump($element->ownerDocument); ?> --EXPECTF-- -object(Dom\XMLDocument)#1 (29) { +object(Dom\XMLDocument)#1 (32) { ["xmlEncoding"]=> string(5) "UTF-8" ["xmlStandalone"]=> @@ -44,6 +44,12 @@ object(Dom\XMLDocument)#1 (29) { string(22) "(object value omitted)" ["childElementCount"]=> int(1) + ["body"]=> + NULL + ["head"]=> + NULL + ["title"]=> + string(0) "" ["nodeType"]=> int(9) ["nodeName"]=>