Support the #[\AllowDynamicProperties] attribute in stubs (#8776)

* Support the `#[\AllowDynamicProperties]` attribute in stubs

* Use `#[\AllowDynamicProperties]` attribute in stubs

* Disallow applying both `@strict-properties` and `#[\AllowDynamicProperties]`
This commit is contained in:
Tim Düsterhus 2022-06-21 09:28:57 +02:00 committed by GitHub
parent 68c234332c
commit ff472ce6fc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 34 additions and 3 deletions

View file

@ -38,8 +38,6 @@ ZEND_MINIT_FUNCTION(core) { /* {{{ */
zend_register_default_classes();
zend_standard_class_def = register_class_stdClass();
zend_add_class_attribute(zend_standard_class_def, zend_ce_allow_dynamic_properties->name, 0);
zend_standard_class_def->ce_flags |= ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES;
return SUCCESS;
}

View file

@ -2,6 +2,7 @@
/** @generate-class-entries */
#[\AllowDynamicProperties]
class stdClass
{
}

View file

@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 33a976db268b72cee985011198125f652bc6c86d */
* Stub hash: 80355bb52d643177e3a661a515d9ea915bd1e2fc */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_version, 0, 0, IS_STRING, 0)
ZEND_END_ARG_INFO()
@ -353,6 +353,8 @@ static zend_class_entry *register_class_stdClass(void)
INIT_CLASS_ENTRY(ce, "stdClass", class_stdClass_methods);
class_entry = zend_register_internal_class_ex(&ce, NULL);
class_entry->ce_flags |= ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES;
zend_add_class_attribute(class_entry, zend_ce_allow_dynamic_properties->name, 0);
return class_entry;
}

View file

@ -2273,6 +2273,8 @@ class ClassInfo {
/** @var bool */
public $isStrictProperties;
/** @var bool */
public $allowsDynamicProperties;
/** @var bool */
public $isNotSerializable;
/** @var Name[] */
public $extends;
@ -2305,6 +2307,7 @@ class ClassInfo {
?SimpleType $enumBackingType,
bool $isDeprecated,
bool $isStrictProperties,
bool $allowsDynamicProperties,
bool $isNotSerializable,
array $extends,
array $implements,
@ -2321,6 +2324,7 @@ class ClassInfo {
$this->enumBackingType = $enumBackingType;
$this->isDeprecated = $isDeprecated;
$this->isStrictProperties = $isStrictProperties;
$this->allowsDynamicProperties = $allowsDynamicProperties;
$this->isNotSerializable = $isNotSerializable;
$this->extends = $extends;
$this->implements = $implements;
@ -2409,6 +2413,10 @@ class ClassInfo {
$code .= $property->getDeclaration($allConstInfos);
}
if ($this->allowsDynamicProperties) {
$code .= "\tzend_add_class_attribute(class_entry, zend_ce_allow_dynamic_properties->name, 0);\n";
}
if ($attributeInitializationCode = generateAttributeInitialization($this->funcInfos, $this->cond)) {
$code .= "\n" . $attributeInitializationCode;
}
@ -2452,6 +2460,10 @@ class ClassInfo {
$flags[] = "ZEND_ACC_NO_DYNAMIC_PROPERTIES";
}
if ($this->allowsDynamicProperties) {
$flags[] = "ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES";
}
if ($this->isNotSerializable) {
$flags[] = "ZEND_ACC_NOT_SERIALIZABLE";
}
@ -3273,6 +3285,7 @@ function parseClass(
$isDeprecated = false;
$isStrictProperties = false;
$isNotSerializable = false;
$allowsDynamicProperties = false;
if ($comment) {
$tags = parseDocComment($comment);
@ -3289,6 +3302,22 @@ function parseClass(
}
}
foreach ($class->attrGroups as $attrGroup) {
foreach ($attrGroup->attrs as $attr) {
switch ($attr->name->toCodeString()) {
case '\\AllowDynamicProperties':
$allowsDynamicProperties = true;
break;
default:
throw new Exception("Unhandled attribute {$attr->name->toCodeString()}.");
}
}
}
if ($isStrictProperties && $allowsDynamicProperties) {
throw new Exception("A class may not have '@strict-properties' and '#[\\AllowDynamicProperties]' at the same time.");
}
$extends = [];
$implements = [];
@ -3319,6 +3348,7 @@ function parseClass(
? SimpleType::fromNode($class->scalarType) : null,
$isDeprecated,
$isStrictProperties,
$allowsDynamicProperties,
$isNotSerializable,
$extends,
$implements,