diff --git a/NEWS b/NEWS index 41584343fc3ea..d92b2cd993940 100644 --- a/NEWS +++ b/NEWS @@ -16,6 +16,7 @@ PHP NEWS - DOM: . Added DOMNode::contains() and DOMNameSpaceNode::contains(). (nielsdos) + . Added DOMNOde::getRootNode(). (nielsdos) - Intl: . Fix memory leak in MessageFormatter::format() on failure. (Girgias) diff --git a/UPGRADING b/UPGRADING index 73c400e047f0d..66152dd2c8943 100644 --- a/UPGRADING +++ b/UPGRADING @@ -240,6 +240,7 @@ PHP 8.3 UPGRADE NOTES - DOM: . Added DOMNode::contains() and DOMNameSpaceNode::contains(). + . Added DOMNOde::getRootNode(). - JSON: . Added json_validate(), which returns whether the json is valid for diff --git a/ext/dom/node.c b/ext/dom/node.c index c5d81ea74ab3b..b9274841666ba 100644 --- a/ext/dom/node.c +++ b/ext/dom/node.c @@ -1818,4 +1818,30 @@ PHP_METHOD(DOMNode, contains) } /* }}} */ +/* {{{ URL: https://dom.spec.whatwg.org/#dom-node-getrootnode +Since: +*/ +PHP_METHOD(DOMNode, getRootNode) +{ + zval *id; + xmlNodePtr thisp; + dom_object *intern; + /* Unused now because we don't support the shadow DOM nodes. Options only influence shadow DOM nodes. */ + zval *options = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|a!", &options) == FAILURE) { + RETURN_THROWS(); + } + + DOM_GET_THIS_OBJ(thisp, id, xmlNodePtr, intern); + + while (thisp->parent) { + thisp = thisp->parent; + } + + int ret; + DOM_RET_OBJ(thisp, &ret, intern); +} +/* }}} */ + #endif diff --git a/ext/dom/php_dom.stub.php b/ext/dom/php_dom.stub.php index 3c3cf649293ee..23fea4ff85d56 100644 --- a/ext/dom/php_dom.stub.php +++ b/ext/dom/php_dom.stub.php @@ -391,6 +391,8 @@ public function removeChild(DOMNode $child) {} public function replaceChild(DOMNode $node, DOMNode $child) {} public function contains(DOMNode|DOMNameSpaceNode|null $other): bool {} + + public function getRootNode(?array $options = null): DOMNode {} } /** @not-serializable */ diff --git a/ext/dom/php_dom_arginfo.h b/ext/dom/php_dom_arginfo.h index cf47f1dae4fcc..576d8f5ed180e 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: fd3acd731f178c2f1034b206b46d53c236823b9f */ + * Stub hash: 82025bbc28e2da02f8ee32f0ec9648fd0d146c10 */ 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) @@ -104,6 +104,10 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_DOMNode_contains, 0, 1, _I ZEND_ARG_OBJ_TYPE_MASK(0, other, DOMNode|DOMNameSpaceNode, MAY_BE_NULL, NULL) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_DOMNode_getRootNode, 0, 0, DOMNode, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null") +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_DOMImplementation_getFeature, 0, 2, IS_NEVER, 0) ZEND_ARG_TYPE_INFO(0, feature, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, version, IS_STRING, 0) @@ -517,6 +521,7 @@ ZEND_METHOD(DOMNode, normalize); ZEND_METHOD(DOMNode, removeChild); ZEND_METHOD(DOMNode, replaceChild); ZEND_METHOD(DOMNode, contains); +ZEND_METHOD(DOMNode, getRootNode); ZEND_METHOD(DOMImplementation, getFeature); ZEND_METHOD(DOMImplementation, hasFeature); ZEND_METHOD(DOMImplementation, createDocumentType); @@ -699,6 +704,7 @@ static const zend_function_entry class_DOMNode_methods[] = { ZEND_ME(DOMNode, removeChild, arginfo_class_DOMNode_removeChild, ZEND_ACC_PUBLIC) ZEND_ME(DOMNode, replaceChild, arginfo_class_DOMNode_replaceChild, ZEND_ACC_PUBLIC) ZEND_ME(DOMNode, contains, arginfo_class_DOMNode_contains, ZEND_ACC_PUBLIC) + ZEND_ME(DOMNode, getRootNode, arginfo_class_DOMNode_getRootNode, ZEND_ACC_PUBLIC) ZEND_FE_END }; diff --git a/ext/dom/tests/DOMNode_getRootNode.phpt b/ext/dom/tests/DOMNode_getRootNode.phpt new file mode 100644 index 0000000000000..b46acbe01d2d8 --- /dev/null +++ b/ext/dom/tests/DOMNode_getRootNode.phpt @@ -0,0 +1,32 @@ +--TEST-- +DOMNode::getRootNode() +--EXTENSIONS-- +dom +--FILE-- +loadXML(''); + +var_dump($dom->documentElement->firstElementChild->getRootNode() === $dom); +$p = $dom->createElement('p'); +var_dump($p->getRootNode() === $p); +$dom->documentElement->appendChild($p); +var_dump($p->getRootNode() === $dom); +$dom->documentElement->remove(); +var_dump($p->getRootNode() === $p); + +$fragment = $dom->createDocumentFragment(); +var_dump($fragment->getRootNode() === $fragment); +$div = $fragment->appendChild($dom->createElement('div')); +$div->appendChild($p); +var_dump($p->getRootNode() === $fragment); + +?> +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true)