Implement DOMElement::className

ref: https://dom.spec.whatwg.org/#dom-element-classname

Closes GH-11691.
This commit is contained in:
Niels Dossche 2023-07-12 20:14:14 +02:00
parent 3d4ff5ae22
commit b24b3510f9
10 changed files with 120 additions and 4 deletions

1
NEWS
View file

@ -19,6 +19,7 @@ PHP NEWS
. Added DOMNode::contains() and DOMNameSpaceNode::contains(). (nielsdos) . Added DOMNode::contains() and DOMNameSpaceNode::contains(). (nielsdos)
. Added DOMElement::getAttributeNames(). (nielsdos) . Added DOMElement::getAttributeNames(). (nielsdos)
. Added DOMNode::getRootNode(). (nielsdos) . Added DOMNode::getRootNode(). (nielsdos)
. Added DOMElement::className. (nielsdos)
- Intl: - Intl:
. Fix memory leak in MessageFormatter::format() on failure. (Girgias) . Fix memory leak in MessageFormatter::format() on failure. (Girgias)

View file

@ -252,6 +252,8 @@ PHP 8.3 UPGRADE NOTES
. Added DOMNode::getRootNode(). The $options argument does nothing at the . Added DOMNode::getRootNode(). The $options argument does nothing at the
moment because it only influences the shadow DOM, which we do not support moment because it only influences the shadow DOM, which we do not support
yet. yet.
. Added DOMElement::className. This is not binary-safe at the moment
because of underlying limitations of libxml2.
- JSON: - JSON:
. Added json_validate(), which returns whether the json is valid for . Added json_validate(), which returns whether the json is valid for

View file

@ -71,6 +71,8 @@ int dom_documenttype_internal_subset_read(dom_object *obj, zval *retval);
/* element properties */ /* element properties */
int dom_element_tag_name_read(dom_object *obj, zval *retval); int dom_element_tag_name_read(dom_object *obj, zval *retval);
int dom_element_class_name_read(dom_object *obj, zval *retval);
int dom_element_class_name_write(dom_object *obj, zval *newval);
int dom_element_schema_type_info_read(dom_object *obj, zval *retval); int dom_element_schema_type_info_read(dom_object *obj, zval *retval);
/* entity properties */ /* entity properties */

View file

@ -137,6 +137,55 @@ int dom_element_tag_name_read(dom_object *obj, zval *retval)
/* }}} */ /* }}} */
/* {{{ className string
URL: https://dom.spec.whatwg.org/#dom-element-classname
Since:
*/
int dom_element_class_name_read(dom_object *obj, zval *retval)
{
xmlNodePtr nodep = dom_object_get_node(obj);
if (nodep == NULL) {
php_dom_throw_error(INVALID_STATE_ERR, 1);
return FAILURE;
}
xmlChar *content = xmlGetNoNsProp(nodep, (const xmlChar *) "class");
if (content == NULL) {
ZVAL_EMPTY_STRING(retval);
return SUCCESS;
}
ZVAL_STRING(retval, (const char *) content);
xmlFree(content);
return SUCCESS;
}
int dom_element_class_name_write(dom_object *obj, zval *newval)
{
xmlNode *nodep = dom_object_get_node(obj);
if (nodep == NULL) {
php_dom_throw_error(INVALID_STATE_ERR, 1);
return FAILURE;
}
if (dom_node_is_read_only(nodep) == SUCCESS) {
php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, dom_get_strict_error(obj->document));
return FAILURE;
}
/* Typed property, so it is a string already */
ZEND_ASSERT(Z_TYPE_P(newval) == IS_STRING);
xmlSetProp(nodep, (const xmlChar *) "class", (const xmlChar *) Z_STRVAL_P(newval));
php_libxml_invalidate_node_list_cache_from_doc(nodep->doc);
return SUCCESS;
}
/* }}} */
/* {{{ schemaTypeInfo typeinfo /* {{{ schemaTypeInfo typeinfo
readonly=yes readonly=yes
URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Element-schemaTypeInfo URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#Element-schemaTypeInfo

View file

@ -751,6 +751,7 @@ PHP_MINIT_FUNCTION(dom)
zend_hash_init(&dom_element_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1); zend_hash_init(&dom_element_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1);
dom_register_prop_handler(&dom_element_prop_handlers, "tagName", sizeof("tagName")-1, dom_element_tag_name_read, NULL); dom_register_prop_handler(&dom_element_prop_handlers, "tagName", sizeof("tagName")-1, dom_element_tag_name_read, NULL);
dom_register_prop_handler(&dom_element_prop_handlers, "className", sizeof("className")-1, dom_element_class_name_read, dom_element_class_name_write);
dom_register_prop_handler(&dom_element_prop_handlers, "schemaTypeInfo", sizeof("schemaTypeInfo")-1, dom_element_schema_type_info_read, NULL); dom_register_prop_handler(&dom_element_prop_handlers, "schemaTypeInfo", sizeof("schemaTypeInfo")-1, dom_element_schema_type_info_read, NULL);
dom_register_prop_handler(&dom_element_prop_handlers, "firstElementChild", sizeof("firstElementChild")-1, dom_parent_node_first_element_child_read, NULL); dom_register_prop_handler(&dom_element_prop_handlers, "firstElementChild", sizeof("firstElementChild")-1, dom_parent_node_first_element_child_read, NULL);
dom_register_prop_handler(&dom_element_prop_handlers, "lastElementChild", sizeof("lastElementChild")-1, dom_parent_node_last_element_child_read, NULL); dom_register_prop_handler(&dom_element_prop_handlers, "lastElementChild", sizeof("lastElementChild")-1, dom_parent_node_last_element_child_read, NULL);

View file

@ -542,6 +542,8 @@ class DOMElement extends DOMNode implements DOMParentNode, DOMChildNode
/** @readonly */ /** @readonly */
public string $tagName; public string $tagName;
public string $className;
/** @readonly */ /** @readonly */
public mixed $schemaTypeInfo = null; public mixed $schemaTypeInfo = null;

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: bba8006906191fa0dd961d65460749a7c7f12afc */ * Stub hash: 91732c51635f43f016f4b531d9aa8e00312084ec */
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)
@ -1374,6 +1374,12 @@ static zend_class_entry *register_class_DOMElement(zend_class_entry *class_entry
zend_declare_typed_property(class_entry, property_tagName_name, &property_tagName_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); zend_declare_typed_property(class_entry, property_tagName_name, &property_tagName_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
zend_string_release(property_tagName_name); zend_string_release(property_tagName_name);
zval property_className_default_value;
ZVAL_UNDEF(&property_className_default_value);
zend_string *property_className_name = zend_string_init("className", sizeof("className") - 1, 1);
zend_declare_typed_property(class_entry, property_className_name, &property_className_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
zend_string_release(property_className_name);
zval property_schemaTypeInfo_default_value; zval property_schemaTypeInfo_default_value;
ZVAL_NULL(&property_schemaTypeInfo_default_value); ZVAL_NULL(&property_schemaTypeInfo_default_value);
zend_string *property_schemaTypeInfo_name = zend_string_init("schemaTypeInfo", sizeof("schemaTypeInfo") - 1, 1); zend_string *property_schemaTypeInfo_name = zend_string_init("schemaTypeInfo", sizeof("schemaTypeInfo") - 1, 1);

View file

@ -0,0 +1,47 @@
--TEST--
DOMElement::className
--EXTENSIONS--
dom
--FILE--
<?php
class MyStringable {
public function __toString(): string {
throw new Exception("foo");
}
}
$dom = new DOMDocument();
$dom->loadXML('<html/>');
var_dump($dom->documentElement->className);
$dom->documentElement->className = "hello & world<>";
var_dump($dom->documentElement->className);
$dom->documentElement->className = "";
var_dump($dom->documentElement->className);
$dom->documentElement->className = "é";
var_dump($dom->documentElement->className);
$dom->documentElement->className = "\0";
var_dump($dom->documentElement->className);
$dom->documentElement->className = 12345;
var_dump($dom->documentElement->className);
try {
$dom->documentElement->className = new MyStringable();
} catch (Throwable $e) {
echo "Error: ", $e->getMessage(), "\n";
}
var_dump($dom->documentElement->className);
echo $dom->saveXML();
?>
--EXPECT--
string(0) ""
string(15) "hello & world<>"
string(0) ""
string(2) "é"
string(0) ""
string(5) "12345"
Error: foo
string(5) "12345"
<?xml version="1.0"?>
<html class="12345"/>

View file

@ -78,11 +78,13 @@ object(DOMText)#%d (21) {
string(3) " string(3) "
" "
} }
object(DOMElement)#7 (23) { object(DOMElement)#7 (24) {
["schemaTypeInfo"]=> ["schemaTypeInfo"]=>
NULL NULL
["tagName"]=> ["tagName"]=>
string(5) "form1" string(5) "form1"
["className"]=>
string(0) ""
["firstElementChild"]=> ["firstElementChild"]=>
string(22) "(object value omitted)" string(22) "(object value omitted)"
["lastElementChild"]=> ["lastElementChild"]=>

View file

@ -21,11 +21,13 @@ var_dump($target);
?> ?>
--EXPECTF-- --EXPECTF--
<a>barfoobaz<last/></a> <a>barfoobaz<last/></a>
object(DOMElement)#3 (23) { object(DOMElement)#3 (24) {
["schemaTypeInfo"]=> ["schemaTypeInfo"]=>
NULL NULL
["tagName"]=> ["tagName"]=>
string(4) "last" string(4) "last"
["className"]=>
string(0) ""
["firstElementChild"]=> ["firstElementChild"]=>
NULL NULL
["lastElementChild"]=> ["lastElementChild"]=>
@ -70,11 +72,13 @@ object(DOMElement)#3 (23) {
string(0) "" string(0) ""
} }
<a><last/>barfoobaz</a> <a><last/>barfoobaz</a>
object(DOMElement)#2 (23) { object(DOMElement)#2 (24) {
["schemaTypeInfo"]=> ["schemaTypeInfo"]=>
NULL NULL
["tagName"]=> ["tagName"]=>
string(4) "last" string(4) "last"
["className"]=>
string(0) ""
["firstElementChild"]=> ["firstElementChild"]=>
NULL NULL
["lastElementChild"]=> ["lastElementChild"]=>