Commit 2945c72a145 for php.net
commit 2945c72a14508363e0d8588c1e3feedd7e1fdde9
Author: David CARLIER <devnexen@gmail.com>
Date: Sat Apr 18 16:47:59 2026 +0100
build/gen_stub: support asymmetric visibility modifiers. (#21773)
Emit ZEND_ACC_PUBLIC_SET / PROTECTED_SET / PRIVATE_SET from the
corresponding Modifiers::*_SET flags in generated arginfo, gated
to PHP 8.4+ where asymmetric visibility was introduced. Previously
private(set) and friends in stubs parsed without error but produced
no set-visibility flag.
@readonly on DOM property stubs was documentation only and did not
translate to any runtime flag, so reflection reported the properties
as writable while the write_property handler threw on assignment.
Declaring them public private(set) lets the engine reject external
writes via the normal visibility check and lets ReflectionProperty::
isWritable() answer honestly.
After converting virtual properties from @readonly to private(set),
dom_write_property still threw a readonly-modification error. Since
the handler replaces zend_std_write_property, the engine's own
asymmetric-visibility check is bypassed on the write path, so the
DOM handler now raises it explicitly via
zend_asymmetric_visibility_property_modification_error() when the
caller lacks set access. The readonly error is kept as a fallback.
diff --git a/build/gen_stub.php b/build/gen_stub.php
index eca1ab3e8c1..e68c0b77c61 100755
--- a/build/gen_stub.php
+++ b/build/gen_stub.php
@@ -2354,7 +2354,17 @@ protected function getFlagsByPhpVersion(): VersionFlags
$flags = "ZEND_ACC_PRIVATE";
}
- return new VersionFlags([$flags]);
+ $versionFlags = new VersionFlags([$flags]);
+
+ if ($this->flags & Modifiers::PUBLIC_SET) {
+ $versionFlags->addForVersionsAbove("ZEND_ACC_PUBLIC_SET", PHP_84_VERSION_ID);
+ } elseif ($this->flags & Modifiers::PROTECTED_SET) {
+ $versionFlags->addForVersionsAbove("ZEND_ACC_PROTECTED_SET", PHP_84_VERSION_ID);
+ } elseif ($this->flags & Modifiers::PRIVATE_SET) {
+ $versionFlags->addForVersionsAbove("ZEND_ACC_PRIVATE_SET", PHP_84_VERSION_ID);
+ }
+
+ return $versionFlags;
}
protected function getTypeCode(string $variableLikeName, string &$code): string
@@ -2450,6 +2460,17 @@ protected function addModifiersToFieldSynopsis(DOMDocument $doc, DOMElement $fie
$fieldsynopsisElement->appendChild(new DOMText("\n$indentation"));
$fieldsynopsisElement->appendChild($doc->createElement("modifier", "private"));
}
+
+ if ($this->flags & Modifiers::PUBLIC_SET) {
+ $fieldsynopsisElement->appendChild(new DOMText("\n$indentation"));
+ $fieldsynopsisElement->appendChild($doc->createElement("modifier", "public(set)"));
+ } elseif ($this->flags & Modifiers::PROTECTED_SET) {
+ $fieldsynopsisElement->appendChild(new DOMText("\n$indentation"));
+ $fieldsynopsisElement->appendChild($doc->createElement("modifier", "protected(set)"));
+ } elseif ($this->flags & Modifiers::PRIVATE_SET) {
+ $fieldsynopsisElement->appendChild(new DOMText("\n$indentation"));
+ $fieldsynopsisElement->appendChild($doc->createElement("modifier", "private(set)"));
+ }
}
}
diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c
index 87b359b2dcb..b188dea6eb4 100644
--- a/ext/dom/php_dom.c
+++ b/ext/dom/php_dom.c
@@ -412,11 +412,6 @@ zval *dom_write_property(zend_object *object, zend_string *name, zval *value, vo
const dom_prop_handler *hnd = dom_get_prop_handler(obj, name, cache_slot);
if (hnd) {
- if (UNEXPECTED(!hnd->write_func)) {
- zend_readonly_property_modification_error_ex(ZSTR_VAL(object->ce->name), ZSTR_VAL(name));
- return &EG(error_zval);
- }
-
zend_property_info *prop = NULL;
if (cache_slot) {
ZEND_ASSERT(*cache_slot == obj->prop_handler);
@@ -429,6 +424,16 @@ zval *dom_write_property(zend_object *object, zend_string *name, zval *value, vo
}
}
+ if (UNEXPECTED(!hnd->write_func)) {
+ if (prop && (prop->flags & ZEND_ACC_PPP_SET_MASK) &&
+ !zend_asymmetric_property_has_set_access(prop)) {
+ zend_asymmetric_visibility_property_modification_error(prop, "modify");
+ } else {
+ zend_readonly_property_modification_error_ex(ZSTR_VAL(object->ce->name), ZSTR_VAL(name));
+ }
+ return &EG(error_zval);
+ }
+
ZEND_ASSERT(prop && ZEND_TYPE_IS_SET(prop->type));
zval tmp;
ZVAL_COPY(&tmp, value);
diff --git a/ext/dom/php_dom.stub.php b/ext/dom/php_dom.stub.php
index 71aa5f4ec0f..521e3cd99c2 100644
--- a/ext/dom/php_dom.stub.php
+++ b/ext/dom/php_dom.stub.php
@@ -237,41 +237,23 @@
class DOMDocumentType extends DOMNode
{
- /**
- * @readonly
- * @virtual
- */
- public string $name;
+ /** @virtual */
+ public private(set) string $name;
- /**
- * @readonly
- * @virtual
- */
- public DOMNamedNodeMap $entities;
+ /** @virtual */
+ public private(set) DOMNamedNodeMap $entities;
- /**
- * @readonly
- * @virtual
- */
- public DOMNamedNodeMap $notations;
+ /** @virtual */
+ public private(set) DOMNamedNodeMap $notations;
- /**
- * @readonly
- * @virtual
- */
- public string $publicId;
+ /** @virtual */
+ public private(set) string $publicId;
- /**
- * @readonly
- * @virtual
- */
- public string $systemId;
+ /** @virtual */
+ public private(set) string $systemId;
- /**
- * @readonly
- * @virtual
- */
- public ?string $internalSubset;
+ /** @virtual */
+ public private(set) ?string $internalSubset;
}
class DOMCdataSection extends DOMText
@@ -319,101 +301,56 @@ class DOMNode
public const int DOCUMENT_POSITION_CONTAINED_BY = 0x10;
public const int DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20;
- /**
- * @readonly
- * @virtual
- */
- public string $nodeName;
+ /** @virtual */
+ public private(set) string $nodeName;
/** @virtual */
public ?string $nodeValue;
- /**
- * @readonly
- * @virtual
- */
- public int $nodeType;
+ /** @virtual */
+ public private(set) int $nodeType;
- /**
- * @readonly
- * @virtual
- */
- public ?DOMNode $parentNode;
+ /** @virtual */
+ public private(set) ?DOMNode $parentNode;
- /**
- * @readonly
- * @virtual
- */
- public ?DOMElement $parentElement;
+ /** @virtual */
+ public private(set) ?DOMElement $parentElement;
- /**
- * @readonly
- * @virtual
- */
- public DOMNodeList $childNodes;
+ /** @virtual */
+ public private(set) DOMNodeList $childNodes;
- /**
- * @readonly
- * @virtual
- */
- public ?DOMNode $firstChild;
+ /** @virtual */
+ public private(set) ?DOMNode $firstChild;
- /**
- * @readonly
- * @virtual
- */
- public ?DOMNode $lastChild;
+ /** @virtual */
+ public private(set) ?DOMNode $lastChild;
- /**
- * @readonly
- * @virtual
- */
- public ?DOMNode $previousSibling;
+ /** @virtual */
+ public private(set) ?DOMNode $previousSibling;
- /**
- * @readonly
- * @virtual
- */
- public ?DOMNode $nextSibling;
+ /** @virtual */
+ public private(set) ?DOMNode $nextSibling;
- /**
- * @readonly
- * @virtual
- */
- public ?DOMNamedNodeMap $attributes;
+ /** @virtual */
+ public private(set) ?DOMNamedNodeMap $attributes;
- /**
- * @readonly
- * @virtual
- */
- public bool $isConnected;
+ /** @virtual */
+ public private(set) bool $isConnected;
- /**
- * @readonly
- * @virtual
- */
- public ?DOMDocument $ownerDocument;
+ /** @virtual */
+ public private(set) ?DOMDocument $ownerDocument;
- /**
- * @readonly
- * @virtual
- */
- public ?string $namespaceURI;
+ /** @virtual */
+ public private(set) ?string $namespaceURI;
/** @virtual */
public string $prefix;
- /**
- * @readonly
- * @virtual
- */
- public ?string $localName;
+ /** @virtual */
+ public private(set) ?string $localName;
- /**
- * @readonly
- * @virtual
- */
- public ?string $baseURI;
+ /** @virtual */
+ public private(set) ?string $baseURI;
/** @virtual */
public string $textContent;
@@ -484,65 +421,35 @@ public function __wakeup(): void {}
class DOMNameSpaceNode
{
- /**
- * @readonly
- * @virtual
- */
- public string $nodeName;
+ /** @virtual */
+ public private(set) string $nodeName;
- /**
- * @readonly
- * @virtual
- */
- public ?string $nodeValue;
+ /** @virtual */
+ public private(set) ?string $nodeValue;
- /**
- * @readonly
- * @virtual
- */
- public int $nodeType;
+ /** @virtual */
+ public private(set) int $nodeType;
- /**
- * @readonly
- * @virtual
- */
- public string $prefix;
+ /** @virtual */
+ public private(set) string $prefix;
- /**
- * @readonly
- * @virtual
- */
- public ?string $localName;
+ /** @virtual */
+ public private(set) ?string $localName;
- /**
- * @readonly
- * @virtual
- */
- public ?string $namespaceURI;
+ /** @virtual */
+ public private(set) ?string $namespaceURI;
- /**
- * @readonly
- * @virtual
- */
- public bool $isConnected;
+ /** @virtual */
+ public private(set) bool $isConnected;
- /**
- * @readonly
- * @virtual
- */
- public ?DOMDocument $ownerDocument;
+ /** @virtual */
+ public private(set) ?DOMDocument $ownerDocument;
- /**
- * @readonly
- * @virtual
- */
- public ?DOMNode $parentNode;
+ /** @virtual */
+ public private(set) ?DOMNode $parentNode;
- /**
- * @readonly
- * @virtual
- */
- public ?DOMElement $parentElement;
+ /** @virtual */
+ public private(set) ?DOMElement $parentElement;
/** @implementation-alias DOMNode::__sleep */
public function __sleep(): array {}
@@ -565,23 +472,14 @@ public function createDocument(?string $namespace = null, string $qualifiedName
class DOMDocumentFragment extends DOMNode implements DOMParentNode
{
- /**
- * @readonly
- * @virtual
- */
- public ?DOMElement $firstElementChild;
+ /** @virtual */
+ public private(set) ?DOMElement $firstElementChild;
- /**
- * @readonly
- * @virtual
- */
- public ?DOMElement $lastElementChild;
+ /** @virtual */
+ public private(set) ?DOMElement $lastElementChild;
- /**
- * @readonly
- * @virtual
- */
- public int $childElementCount;
+ /** @virtual */
+ public private(set) int $childElementCount;
public function __construct() {}
@@ -609,11 +507,8 @@ public function replaceChildren(...$nodes): void {}
class DOMNodeList implements IteratorAggregate, Countable
{
- /**
- * @readonly
- * @virtual
- */
- public int $length;
+ /** @virtual */
+ public private(set) int $length;
/** @tentative-return-type */
public function count(): int {}
@@ -629,23 +524,14 @@ class DOMCharacterData extends DOMNode implements DOMChildNode
/** @virtual */
public string $data;
- /**
- * @readonly
- * @virtual
- */
- public int $length;
+ /** @virtual */
+ public private(set) int $length;
- /**
- * @readonly
- * @virtual
- */
- public ?DOMElement $previousElementSibling;
+ /** @virtual */
+ public private(set) ?DOMElement $previousElementSibling;
- /**
- * @readonly
- * @virtual
- */
- public ?DOMElement $nextElementSibling;
+ /** @virtual */
+ public private(set) ?DOMElement $nextElementSibling;
/** @tentative-return-type */
public function appendData(string $data): true {}
@@ -686,32 +572,20 @@ public function after(...$nodes): void {}
class DOMAttr extends DOMNode
{
- /**
- * @readonly
- * @virtual
- */
- public string $name;
+ /** @virtual */
+ public private(set) string $name;
- /**
- * @readonly
- * @virtual
- */
- public bool $specified;
+ /** @virtual */
+ public private(set) bool $specified;
/** @virtual */
public string $value;
- /**
- * @readonly
- * @virtual
- */
- public ?DOMElement $ownerElement;
+ /** @virtual */
+ public private(set) ?DOMElement $ownerElement;
- /**
- * @readonly
- * @virtual
- */
- public mixed $schemaTypeInfo;
+ /** @virtual */
+ public private(set) mixed $schemaTypeInfo;
public function __construct(string $name, string $value = "") {}
@@ -721,11 +595,8 @@ public function isId(): bool {}
class DOMElement extends DOMNode implements \DOMParentNode, \DOMChildNode
{
- /**
- * @readonly
- * @virtual
- */
- public string $tagName;
+ /** @virtual */
+ public private(set) string $tagName;
/** @virtual */
public string $className;
@@ -733,41 +604,23 @@ class DOMElement extends DOMNode implements \DOMParentNode, \DOMChildNode
/** @virtual */
public string $id;
- /**
- * @readonly
- * @virtual
- */
- public mixed $schemaTypeInfo;
+ /** @virtual */
+ public private(set) mixed $schemaTypeInfo;
- /**
- * @readonly
- * @virtual
- */
- public ?DOMElement $firstElementChild;
+ /** @virtual */
+ public private(set) ?DOMElement $firstElementChild;
- /**
- * @readonly
- * @virtual
- */
- public ?DOMElement $lastElementChild;
+ /** @virtual */
+ public private(set) ?DOMElement $lastElementChild;
- /**
- * @readonly
- * @virtual
- */
- public int $childElementCount;
+ /** @virtual */
+ public private(set) int $childElementCount;
- /**
- * @readonly
- * @virtual
- */
- public ?DOMElement $previousElementSibling;
+ /** @virtual */
+ public private(set) ?DOMElement $previousElementSibling;
- /**
- * @readonly
- * @virtual
- */
- public ?DOMElement $nextElementSibling;
+ /** @virtual */
+ public private(set) ?DOMElement $nextElementSibling;
public function __construct(string $qualifiedName, ?string $value = null, string $namespace = "") {}
@@ -856,39 +709,26 @@ public function insertAdjacentText(string $where, string $data): void {}
class DOMDocument extends DOMNode implements DOMParentNode
{
- /**
- * @readonly
- * @virtual
- */
- public ?DOMDocumentType $doctype;
+ /** @virtual */
+ public private(set) ?DOMDocumentType $doctype;
- /**
- * @readonly
- * @virtual
- */
- public DOMImplementation $implementation;
+ /** @virtual */
+ public private(set) DOMImplementation $implementation;
- /**
- * @readonly
- * @virtual
- */
- public ?DOMElement $documentElement;
+ /** @virtual */
+ public private(set) ?DOMElement $documentElement;
/**
- * @readonly
* @deprecated
* @virtual
*/
- public ?string $actualEncoding;
+ public private(set) ?string $actualEncoding;
/** @virtual */
public ?string $encoding;
- /**
- * @readonly
- * @virtual
- */
- public ?string $xmlEncoding;
+ /** @virtual */
+ public private(set) ?string $xmlEncoding;
/** @virtual */
public bool $standalone;
@@ -909,11 +749,10 @@ class DOMDocument extends DOMNode implements DOMParentNode
public ?string $documentURI;
/**
- * @readonly
* @deprecated
* @virtual
*/
- public mixed $config;
+ public private(set) mixed $config;
/** @virtual */
public bool $formatOutput;
@@ -933,23 +772,14 @@ class DOMDocument extends DOMNode implements DOMParentNode
/** @virtual */
public bool $substituteEntities;
- /**
- * @readonly
- * @virtual
- */
- public ?DOMElement $firstElementChild;
+ /** @virtual */
+ public private(set) ?DOMElement $firstElementChild;
- /**
- * @readonly
- * @virtual
- */
- public ?DOMElement $lastElementChild;
+ /** @virtual */
+ public private(set) ?DOMElement $lastElementChild;
- /**
- * @readonly
- * @virtual
- */
- public int $childElementCount;
+ /** @virtual */
+ public private(set) int $childElementCount;
public function __construct(string $version = "1.0", string $encoding = "") {}
@@ -1082,11 +912,8 @@ final class DOMException extends Exception
class DOMText extends DOMCharacterData
{
- /**
- * @readonly
- * @virtual
- */
- public string $wholeText;
+ /** @virtual */
+ public private(set) string $wholeText;
public function __construct(string $data = "") {}
@@ -1105,11 +932,8 @@ public function splitText(int $offset) {}
class DOMNamedNodeMap implements IteratorAggregate, Countable
{
- /**
- * @readonly
- * @virtual
- */
- public int $length;
+ /** @virtual */
+ public private(set) int $length;
/** @tentative-return-type */
public function getNamedItem(string $qualifiedName): ?DOMNode {}
@@ -1128,44 +952,32 @@ public function getIterator(): Iterator {}
class DOMEntity extends DOMNode
{
- /**
- * @readonly
- * @virtual
- */
- public ?string $publicId;
+ /** @virtual */
+ public private(set) ?string $publicId;
- /**
- * @readonly
- * @virtual
- */
- public ?string $systemId;
+ /** @virtual */
+ public private(set) ?string $systemId;
- /**
- * @readonly
- * @virtual
- */
- public ?string $notationName;
+ /** @virtual */
+ public private(set) ?string $notationName;
/**
- * @readonly
* @deprecated
* @virtual
*/
- public ?string $actualEncoding;
+ public private(set) ?string $actualEncoding;
/**
- * @readonly
* @deprecated
* @virtual
*/
- public ?string $encoding;
+ public private(set) ?string $encoding;
/**
- * @readonly
* @deprecated
* @virtual
*/
- public ?string $version;
+ public private(set) ?string $version;
}
class DOMEntityReference extends DOMNode
@@ -1175,26 +987,17 @@ public function __construct(string $name) {}
class DOMNotation extends DOMNode
{
- /**
- * @readonly
- * @virtual
- */
- public string $publicId;
+ /** @virtual */
+ public private(set) string $publicId;
- /**
- * @readonly
- * @virtual
- */
- public string $systemId;
+ /** @virtual */
+ public private(set) string $systemId;
}
class DOMProcessingInstruction extends DOMNode
- {
- /**
- * @readonly
- * @virtual
- */
- public string $target;
+ {
+ /** @virtual */
+ public private(set) string $target;
/** @virtual */
public string $data;
@@ -1206,11 +1009,8 @@ public function __construct(string $name, string $value = "") {}
/** @not-serializable */
class DOMXPath
{
- /**
- * @readonly
- * @virtual
- */
- public DOMDocument $document;
+ /** @virtual */
+ public private(set) DOMDocument $document;
/** @virtual */
public bool $registerNodeNamespaces;
@@ -1358,73 +1158,37 @@ class Node
{
private final function __construct() {}
- /**
- * @readonly
- * @virtual
- */
- public int $nodeType;
- /**
- * @readonly
- * @virtual
- */
- public string $nodeName;
+ /** @virtual */
+ public private(set) int $nodeType;
+ /** @virtual */
+ public private(set) string $nodeName;
- /**
- * @readonly
- * @virtual
- */
- public string $baseURI;
+ /** @virtual */
+ public private(set) string $baseURI;
- /**
- * @readonly
- * @virtual
- */
- public bool $isConnected;
- /**
- * @readonly
- * @virtual
- */
- public ?Document $ownerDocument;
+ /** @virtual */
+ public private(set) bool $isConnected;
+ /** @virtual */
+ public private(set) ?Document $ownerDocument;
/** @implementation-alias DOMNode::getRootNode */
public function getRootNode(array $options = []): Node {}
- /**
- * @readonly
- * @virtual
- */
- public ?Node $parentNode;
- /**
- * @readonly
- * @virtual
- */
- public ?Element $parentElement;
+ /** @virtual */
+ public private(set) ?Node $parentNode;
+ /** @virtual */
+ public private(set) ?Element $parentElement;
/** @implementation-alias DOMNode::hasChildNodes */
public function hasChildNodes(): bool {}
- /**
- * @readonly
- * @virtual
- */
- public NodeList $childNodes;
- /**
- * @readonly
- * @virtual
- */
- public ?Node $firstChild;
- /**
- * @readonly
- * @virtual
- */
- public ?Node $lastChild;
- /**
- * @readonly
- * @virtual
- */
- public ?Node $previousSibling;
- /**
- * @readonly
- * @virtual
- */
- public ?Node $nextSibling;
+ /** @virtual */
+ public private(set) NodeList $childNodes;
+ /** @virtual */
+ public private(set) ?Node $firstChild;
+ /** @virtual */
+ public private(set) ?Node $lastChild;
+ /** @virtual */
+ public private(set) ?Node $previousSibling;
+ /** @virtual */
+ public private(set) ?Node $nextSibling;
/** @virtual */
public ?string $nodeValue;
@@ -1474,11 +1238,8 @@ public function __wakeup(): void {}
class NodeList implements \IteratorAggregate, \Countable
{
- /**
- * @readonly
- * @virtual
- */
- public int $length;
+ /** @virtual */
+ public private(set) int $length;
/** @implementation-alias DOMNodeList::count */
public function count(): int {}
@@ -1492,11 +1253,8 @@ public function item(int $index): ?Node {}
class NamedNodeMap implements \IteratorAggregate, \Countable
{
- /**
- * @readonly
- * @virtual
- */
- public int $length;
+ /** @virtual */
+ public private(set) int $length;
/** @implementation-alias DOMNamedNodeMap::item */
public function item(int $index): ?Attr {}
@@ -1514,11 +1272,8 @@ public function getIterator(): \Iterator {}
class DtdNamedNodeMap implements \IteratorAggregate, \Countable
{
- /**
- * @readonly
- * @virtual
- */
- public int $length;
+ /** @virtual */
+ public private(set) int $length;
/** @implementation-alias DOMNamedNodeMap::item */
public function item(int $index): Entity|Notation|null {}
@@ -1536,11 +1291,8 @@ public function getIterator(): \Iterator {}
class HTMLCollection implements \IteratorAggregate, \Countable
{
- /**
- * @readonly
- * @virtual
- */
- public int $length;
+ /** @virtual */
+ public private(set) int $length;
/** @implementation-alias DOMNodeList::item */
public function item(int $index): ?Element {}
@@ -1564,71 +1316,37 @@ enum AdjacentPosition : string
class Element extends Node implements ParentNode, ChildNode
{
- /**
- * @readonly
- * @virtual
- */
- public ?string $namespaceURI;
- /**
- * @readonly
- * @virtual
- */
- public ?string $prefix;
- /**
- * @readonly
- * @virtual
- */
- public string $localName;
- /**
- * @readonly
- * @virtual
- */
- public string $tagName;
+ /** @virtual */
+ public private(set) ?string $namespaceURI;
+ /** @virtual */
+ public private(set) ?string $prefix;
+ /** @virtual */
+ public private(set) string $localName;
+ /** @virtual */
+ public private(set) string $tagName;
- /**
- * @readonly
- */
- public HTMLCollection $children;
- /**
- * @readonly
- * @virtual
- */
- public ?Element $firstElementChild;
- /**
- * @readonly
- * @virtual
- */
- public ?Element $lastElementChild;
- /**
- * @readonly
- * @virtual
- */
- public int $childElementCount;
- /**
- * @readonly
- * @virtual
- */
- public ?Element $previousElementSibling;
- /**
- * @readonly
- * @virtual
- */
- public ?Element $nextElementSibling;
+ public private(set) HTMLCollection $children;
+ /** @virtual */
+ public private(set) ?Element $firstElementChild;
+ /** @virtual */
+ public private(set) ?Element $lastElementChild;
+ /** @virtual */
+ public private(set) int $childElementCount;
+ /** @virtual */
+ public private(set) ?Element $previousElementSibling;
+ /** @virtual */
+ public private(set) ?Element $nextElementSibling;
/** @virtual */
public string $id;
/** @virtual */
public string $className;
- /** @readonly */
- public TokenList $classList;
+ public private(set) TokenList $classList;
/** @implementation-alias DOMNode::hasAttributes */
public function hasAttributes(): bool {}
- /**
- * @readonly
- * @virtual
- */
- public NamedNodeMap $attributes;
+ /** @virtual */
+ public private(set) NamedNodeMap $attributes;
/** @implementation-alias DOMElement::getAttributeNames */
public function getAttributeNames(): array {}
/** @implementation-alias DOMElement::getAttribute */
@@ -1716,40 +1434,22 @@ class HTMLElement extends Element
class Attr extends Node
{
- /**
- * @readonly
- * @virtual
- */
- public ?string $namespaceURI;
- /**
- * @readonly
- * @virtual
- */
- public ?string $prefix;
- /**
- * @readonly
- * @virtual
- */
- public string $localName;
- /**
- * @readonly
- * @virtual
- */
- public string $name;
+ /** @virtual */
+ public private(set) ?string $namespaceURI;
+ /** @virtual */
+ public private(set) ?string $prefix;
+ /** @virtual */
+ public private(set) string $localName;
+ /** @virtual */
+ public private(set) string $name;
/** @virtual */
public string $value;
- /**
- * @readonly
- * @virtual
- */
- public ?Element $ownerElement;
+ /** @virtual */
+ public private(set) ?Element $ownerElement;
- /**
- * @readonly
- * @virtual
- */
- public bool $specified;
+ /** @virtual */
+ public private(set) bool $specified;
/** @implementation-alias DOMAttr::isId */
public function isId(): bool {}
@@ -1760,24 +1460,15 @@ public function rename(?string $namespaceURI, string $qualifiedName): void {}
class CharacterData extends Node implements ChildNode
{
- /**
- * @readonly
- * @virtual
- */
- public ?Element $previousElementSibling;
- /**
- * @readonly
- * @virtual
- */
- public ?Element $nextElementSibling;
+ /** @virtual */
+ public private(set) ?Element $previousElementSibling;
+ /** @virtual */
+ public private(set) ?Element $nextElementSibling;
/** @virtual */
public string $data;
- /**
- * @readonly
- * @virtual
- */
- public int $length;
+ /** @virtual */
+ public private(set) int $length;
/** @implementation-alias DOMCharacterData::substringData */
public function substringData(int $offset, int $count): string {}
public function appendData(string $data): void {}
@@ -1801,22 +1492,16 @@ class Text extends CharacterData
/** @implementation-alias DOMText::splitText */
public function splitText(int $offset): Text {}
- /**
- * @readonly
- * @virtual
- */
- public string $wholeText;
+ /** @virtual */
+ public private(set) string $wholeText;
}
class CDATASection extends Text {}
class ProcessingInstruction extends CharacterData
{
- /**
- * @readonly
- * @virtual
- */
- public string $target;
+ /** @virtual */
+ public private(set) string $target;
}
class Comment extends CharacterData
@@ -1826,36 +1511,18 @@ class Comment extends CharacterData
class DocumentType extends Node implements ChildNode
{
- /**
- * @readonly
- * @virtual
- */
- public string $name;
- /**
- * @readonly
- * @virtual
- */
- public DtdNamedNodeMap $entities;
- /**
- * @readonly
- * @virtual
- */
- public DtdNamedNodeMap $notations;
- /**
- * @readonly
- * @virtual
- */
- public string $publicId;
- /**
- * @readonly
- * @virtual
- */
- public string $systemId;
- /**
- * @readonly
- * @virtual
- */
- public ?string $internalSubset;
+ /** @virtual */
+ public private(set) string $name;
+ /** @virtual */
+ public private(set) DtdNamedNodeMap $entities;
+ /** @virtual */
+ public private(set) DtdNamedNodeMap $notations;
+ /** @virtual */
+ public private(set) string $publicId;
+ /** @virtual */
+ public private(set) string $systemId;
+ /** @virtual */
+ public private(set) ?string $internalSubset;
/** @implementation-alias DOMElement::remove */
public function remove(): void {}
@@ -1869,25 +1536,13 @@ public function replaceWith(Node|string ...$nodes): void {}
class DocumentFragment extends Node implements ParentNode
{
- /**
- * @readonly
- */
- public HTMLCollection $children;
- /**
- * @readonly
- * @virtual
- */
- public ?Element $firstElementChild;
- /**
- * @readonly
- * @virtual
- */
- public ?Element $lastElementChild;
- /**
- * @readonly
- * @virtual
- */
- public int $childElementCount;
+ public private(set) HTMLCollection $children;
+ /** @virtual */
+ public private(set) ?Element $firstElementChild;
+ /** @virtual */
+ public private(set) ?Element $lastElementChild;
+ /** @virtual */
+ public private(set) int $childElementCount;
/** @implementation-alias DOMDocumentFragment::appendXML */
public function appendXml(string $data): bool {}
@@ -1906,63 +1561,35 @@ public function querySelectorAll(string $selectors): NodeList {}
class Entity extends Node
{
- /**
- * @readonly
- * @virtual
- */
- public ?string $publicId;
- /**
- * @readonly
- * @virtual
- */
- public ?string $systemId;
- /**
- * @readonly
- * @virtual
- */
- public ?string $notationName;
+ /** @virtual */
+ public private(set) ?string $publicId;
+ /** @virtual */
+ public private(set) ?string $systemId;
+ /** @virtual */
+ public private(set) ?string $notationName;
}
class EntityReference extends Node {}
class Notation extends Node
{
- /**
- * @readonly
- * @virtual
- */
- public string $publicId;
- /**
- * @readonly
- * @virtual
- */
- public string $systemId;
+ /** @virtual */
+ public private(set) string $publicId;
+ /** @virtual */
+ public private(set) string $systemId;
}
abstract class Document extends Node implements ParentNode
{
- /**
- * @readonly
- */
- public HTMLCollection $children;
- /**
- * @readonly
- * @virtual
- */
- public ?Element $firstElementChild;
- /**
- * @readonly
- * @virtual
- */
- public ?Element $lastElementChild;
- /**
- * @readonly
- * @virtual
- */
- public int $childElementCount;
+ public private(set) HTMLCollection $children;
+ /** @virtual */
+ public private(set) ?Element $firstElementChild;
+ /** @virtual */
+ public private(set) ?Element $lastElementChild;
+ /** @virtual */
+ public private(set) int $childElementCount;
- /** @readonly */
- public Implementation $implementation;
+ public private(set) Implementation $implementation;
/** @virtual */
public string $URL;
/** @virtual */
@@ -1974,16 +1601,10 @@ abstract class Document extends Node implements ParentNode
/** @virtual */
public string $inputEncoding;
- /**
- * @readonly
- * @virtual
- */
- public ?DocumentType $doctype;
- /**
- * @readonly
- * @virtual
- */
- public ?Element $documentElement;
+ /** @virtual */
+ public private(set) ?DocumentType $doctype;
+ /** @virtual */
+ public private(set) ?Element $documentElement;
/** @implementation-alias Dom\Element::getElementsByTagName */
public function getElementsByTagName(string $qualifiedName): HTMLCollection {}
/** @implementation-alias Dom\Element::getElementsByTagNameNS */
@@ -2043,11 +1664,8 @@ public function querySelectorAll(string $selectors): NodeList {}
/** @virtual */
public ?HTMLElement $body;
- /**
- * @readonly
- * @virtual
- */
- public ?HTMLElement $head;
+ /** @virtual */
+ public private(set) ?HTMLElement $head;
/** @virtual */
public string $title;
}
@@ -2083,11 +1701,8 @@ public static function createFromFile(string $path, int $options = 0, ?string $o
public static function createFromString(string $source, int $options = 0, ?string $overrideEncoding = null): XMLDocument {}
- /**
- * @readonly
- * @virtual
- */
- public string $xmlEncoding;
+ /** @virtual */
+ public private(set) string $xmlEncoding;
/** @virtual */
public bool $xmlStandalone;
@@ -2121,11 +1736,8 @@ final class TokenList implements \IteratorAggregate, \Countable
/** @implementation-alias Dom\Node::__construct */
private function __construct() {}
- /**
- * @readonly
- * @virtual
- */
- public int $length;
+ /** @virtual */
+ public private(set) int $length;
public function item(int $index): ?string {}
public function contains(string $token): bool {}
public function add(string ...$tokens): void {}
@@ -2159,11 +1771,8 @@ private function __construct() {}
/** @not-serializable */
final class XPath
{
- /**
- * @readonly
- * @virtual
- */
- public Document $document;
+ /** @virtual */
+ public private(set) Document $document;
/** @virtual */
public bool $registerNodeNamespaces;
diff --git a/ext/dom/php_dom_arginfo.h b/ext/dom/php_dom_arginfo.h
index 1c90f920cdd..0274186380d 100644
Binary files a/ext/dom/php_dom_arginfo.h and b/ext/dom/php_dom_arginfo.h differ
diff --git a/ext/dom/php_dom_decl.h b/ext/dom/php_dom_decl.h
index f918637ab52..e42fe596959 100644
Binary files a/ext/dom/php_dom_decl.h and b/ext/dom/php_dom_decl.h differ
diff --git a/ext/dom/tests/modern/spec/Element_prefix_readonly.phpt b/ext/dom/tests/modern/spec/Element_prefix_readonly.phpt
index 78625fcb6f7..cb623f70298 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 @@
echo $dom->saveXml();
?>
--EXPECT--
-Cannot modify readonly property Dom\HTMLElement::$prefix
+Cannot modify private(set) property Dom\Element::$prefix from global scope
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
diff --git a/ext/dom/tests/property_write_errors.phpt b/ext/dom/tests/property_write_errors.phpt
index 58cf800728a..7d2af3b1055 100644
--- a/ext/dom/tests/property_write_errors.phpt
+++ b/ext/dom/tests/property_write_errors.phpt
@@ -49,8 +49,8 @@
?>
--EXPECT--
Cannot assign array to property DOMNode::$nodeValue of type ?string
-Cannot modify readonly property DOMDocument::$nodeType
-Cannot modify readonly property DOMDocument::$xmlEncoding
-Cannot modify readonly property DOMEntity::$actualEncoding
-Cannot modify readonly property DOMEntity::$encoding
-Cannot modify readonly property DOMEntity::$version
+Cannot modify private(set) property DOMNode::$nodeType from global scope
+Cannot modify private(set) property DOMDocument::$xmlEncoding from global scope
+Cannot modify private(set) property DOMEntity::$actualEncoding from global scope
+Cannot modify private(set) property DOMEntity::$encoding from global scope
+Cannot modify private(set) property DOMEntity::$version from global scope