From 006759e0b3a34a33e9c9320367ac85aae40ab9bf Mon Sep 17 00:00:00 2001 From: PurHur Date: Sat, 11 Jul 2026 05:02:27 +0000 Subject: [PATCH] ext/dom: initialize DOMElement::tagName slot on createElement (#3326) Register tagName on DOMElement and populate it alongside nodeName so JIT/AOT property-slot reads match VM DomNodePropertySupport parity. Co-authored-by: Cursor --- ext/dom/VmDom.php | 7 +++++++ test/compliance/DomDocumentVMTest.php | 4 ++++ test/compliance/cases/stdlib/dom_element_tag_name.phpt | 10 ++++++++++ test/repro/maintainer_gap_dom_element_tag_name_jit.php | 7 +++++++ 4 files changed, 28 insertions(+) create mode 100644 test/compliance/cases/stdlib/dom_element_tag_name.phpt create mode 100644 test/repro/maintainer_gap_dom_element_tag_name_jit.php diff --git a/ext/dom/VmDom.php b/ext/dom/VmDom.php index e8bb2126051..895ef58d425 100644 --- a/ext/dom/VmDom.php +++ b/ext/dom/VmDom.php @@ -570,6 +570,7 @@ public static function registerClasses(Context $ctx): void $element->isInternal = true; $element->parentLc = self::CLASS_NODE; $element->properties[] = new ClassProperty(self::PROP_NODE_NAME, null, $strProto); + $element->properties[] = new ClassProperty(self::PROP_TAG_NAME, null, $strProto); $element->properties[] = new ClassProperty(self::PROP_ATTRIBUTES, $nullProto, $objProto); $element->methods['appendchild'] = new ElementAppendChild(); $element->methodVisibility['appendchild'] = $pub; @@ -857,6 +858,9 @@ public static function createElement( $entry = new ObjectEntry($class); $entry->constructed = true; $entry->getProperty(self::PROP_NODE_NAME)->string($name); + if ($entry->hasProperty(self::PROP_TAG_NAME)) { + $entry->getProperty(self::PROP_TAG_NAME)->string($name); + } self::initElementPropertySlots($entry); $state = new DomNodeState(); @@ -896,6 +900,9 @@ public static function createElementNS( $entry = new ObjectEntry($class); $entry->constructed = true; $entry->getProperty(self::PROP_NODE_NAME)->string($qualifiedName); + if ($entry->hasProperty(self::PROP_TAG_NAME)) { + $entry->getProperty(self::PROP_TAG_NAME)->string($qualifiedName); + } self::initElementPropertySlots($entry); $state = new DomNodeState(); diff --git a/test/compliance/DomDocumentVMTest.php b/test/compliance/DomDocumentVMTest.php index 35f100dc42b..9d4054562f3 100644 --- a/test/compliance/DomDocumentVMTest.php +++ b/test/compliance/DomDocumentVMTest.php @@ -45,6 +45,10 @@ public static function providePHPTests(): \Generator __DIR__.'/cases/stdlib/dom_create_element_ns.phpt', 'dom_create_element_ns.phpt' ); + yield 'dom_element_tag_name.phpt' => self::parsePHPT( + __DIR__.'/cases/stdlib/dom_element_tag_name.phpt', + 'dom_element_tag_name.phpt' + ); yield 'dom_namespace_attributes.phpt' => self::parsePHPT( __DIR__.'/cases/stdlib/dom_namespace_attributes.phpt', 'dom_namespace_attributes.phpt' diff --git a/test/compliance/cases/stdlib/dom_element_tag_name.phpt b/test/compliance/cases/stdlib/dom_element_tag_name.phpt new file mode 100644 index 00000000000..30144d4ebe3 --- /dev/null +++ b/test/compliance/cases/stdlib/dom_element_tag_name.phpt @@ -0,0 +1,10 @@ +--TEST-- +DOMElement::tagName readable after createElement (ext/dom/node.c, #3326) +--FILE-- +createElement('item'); +echo $el->tagName, "\n"; +--EXPECT-- +item diff --git a/test/repro/maintainer_gap_dom_element_tag_name_jit.php b/test/repro/maintainer_gap_dom_element_tag_name_jit.php new file mode 100644 index 00000000000..2ce9a1ab9be --- /dev/null +++ b/test/repro/maintainer_gap_dom_element_tag_name_jit.php @@ -0,0 +1,7 @@ +createElement('p'); +echo $el->nodeName, ':', $el->tagName;