1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Implement DOMNode::contains()

ref: https://dom.spec.whatwg.org/#dom-node-contains
This commit is contained in:
Niels Dossche
2023-07-11 22:34:39 +02:00
parent 2aaa7997a2
commit ea794e9cde
6 changed files with 160 additions and 1 deletions

3
NEWS
View File

@@ -14,6 +14,9 @@ PHP NEWS
. Added zend_call_stack_get implementation for OpenBSD. (David Carlier)
. Fixed oss-fuzz #60411 (Fix double-compilation of arrow-functions). (ilutov)
- DOM:
. Added DOMNode::contains() and DOMNameSpaceNode::contains(). (nielsdos)
- Intl:
. Fix memory leak in MessageFormatter::format() on failure. (Girgias)

View File

@@ -238,6 +238,9 @@ PHP 8.3 UPGRADE NOTES
6. New Functions
========================================
- DOM:
. Added DOMNode::contains() and DOMNameSpaceNode::contains().
- JSON:
. Added json_validate(), which returns whether the json is valid for
the given $depth and $options.

View File

@@ -1782,4 +1782,40 @@ PHP_METHOD(DOMNode, getLineNo)
}
/* }}} */
/* {{{ URL: https://dom.spec.whatwg.org/#dom-node-contains
Since:
*/
PHP_METHOD(DOMNode, contains)
{
zval *other, *id;
xmlNodePtr otherp, thisp;
dom_object *unused_intern;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_OBJECT_OR_NULL(other)
ZEND_PARSE_PARAMETERS_END();
if (other == NULL) {
RETURN_FALSE;
}
if (UNEXPECTED(!instanceof_function(Z_OBJCE_P(other), dom_node_class_entry) && !instanceof_function(Z_OBJCE_P(other), dom_namespace_node_class_entry))) {
zend_argument_type_error(1, "must be of type DOMNode|DOMNameSpaceNode|null, %s given", zend_zval_value_name(other));
RETURN_THROWS();
}
DOM_GET_OBJ(otherp, other, xmlNodePtr, unused_intern);
DOM_GET_THIS_OBJ(thisp, id, xmlNodePtr, unused_intern);
do {
if (otherp == thisp) {
RETURN_TRUE;
}
otherp = otherp->parent;
} while (otherp);
RETURN_FALSE;
}
/* }}} */
#endif

View File

@@ -389,6 +389,8 @@ class DOMNode
/** @return DOMNode|false */
public function replaceChild(DOMNode $node, DOMNode $child) {}
public function contains(DOMNode|DOMNameSpaceNode|null $other): bool {}
}
/** @not-serializable */

View File

@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 00d59fd45c44eb14bbf8f51ee4f61e0464786d69 */
* Stub hash: fd3acd731f178c2f1034b206b46d53c236823b9f */
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)
@@ -100,6 +100,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DOMNode_replaceChild, 0, 0, 2)
ZEND_ARG_OBJ_INFO(0, child, DOMNode, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_DOMNode_contains, 0, 1, _IS_BOOL, 0)
ZEND_ARG_OBJ_TYPE_MASK(0, other, DOMNode|DOMNameSpaceNode, MAY_BE_NULL, 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)
@@ -512,6 +516,7 @@ ZEND_METHOD(DOMNode, lookupPrefix);
ZEND_METHOD(DOMNode, normalize);
ZEND_METHOD(DOMNode, removeChild);
ZEND_METHOD(DOMNode, replaceChild);
ZEND_METHOD(DOMNode, contains);
ZEND_METHOD(DOMImplementation, getFeature);
ZEND_METHOD(DOMImplementation, hasFeature);
ZEND_METHOD(DOMImplementation, createDocumentType);
@@ -693,6 +698,7 @@ static const zend_function_entry class_DOMNode_methods[] = {
ZEND_ME(DOMNode, normalize, arginfo_class_DOMNode_normalize, ZEND_ACC_PUBLIC)
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_FE_END
};

View File

@@ -0,0 +1,109 @@
--TEST--
DOMNode::contains()
--EXTENSIONS--
dom
--FILE--
<?php
$dom = new DOMDocument();
$dom->loadXML(<<<XML
<!DOCTYPE HTML>
<html xmlns:test="some:ns">
<head>
<title>my title</title>
</head>
<body>
<main>
<p>Hello, world!</p>
<p>Second paragraph</p>
<div><p>container</p></div>
<!-- comment -->
</main>
</body>
</html>
XML);
$xpath = new DOMXPath($dom);
$head = $xpath->query("//head")[0];
$main = $xpath->query("//main")[0];
$div = $xpath->query("//div")[0];
echo "--- False edge cases ---\n";
var_dump($dom->documentElement->contains(null));
try {
var_dump($dom->contains(new stdClass));
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
echo "--- True cases ---\n";
var_dump($dom->documentElement->contains($head));
var_dump($dom->documentElement->contains($main));
var_dump($dom->contains($dom));
var_dump($main->contains($main));
var_dump($div->contains($div));
var_dump($main->contains($div));
var_dump($main->contains($main->firstElementChild));
var_dump($main->contains($div->firstElementChild));
var_dump($div->contains($div->firstElementChild));
var_dump($main->contains($main->firstElementChild->firstChild));
var_dump($dom->contains($dom->doctype));
var_dump($dom->contains($dom->doctype));
var_dump($dom->contains($dom->documentElement->getAttributeNode('xmlns:test')));
var_dump($dom->contains($main->lastChild));
echo "--- False cases ---\n";
var_dump($main->firstElementChild->contains($main));
var_dump($main->contains($head));
var_dump($div->contains($main));
var_dump($main->contains($head->firstElementChild));
var_dump($div->contains($main->firstElementChild));
var_dump($div->contains($main->firstElementChild->nextElementSibling));
var_dump($div->contains($main->lastChild));
echo "--- False, create element case ---\n";
$newElement = $dom->createElement('x');
var_dump($dom->documentElement->contains($newElement));
echo "--- Removal case ---\n";
$main->remove();
var_dump($main->contains($main));
var_dump($dom->contains($main));
?>
--EXPECT--
--- False edge cases ---
bool(false)
DOMNode::contains(): Argument #1 ($other) must be of type DOMNode|DOMNameSpaceNode|null, stdClass given
--- True cases ---
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
--- False cases ---
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
--- False, create element case ---
bool(false)
--- Removal case ---
bool(true)
bool(false)