diff --git a/Zend/zend_attributes.c b/Zend/zend_attributes.c index 6330887b29084..5a446c8c2859e 100644 --- a/Zend/zend_attributes.c +++ b/Zend/zend_attributes.c @@ -317,27 +317,39 @@ static void free_internal_attribute(zval *v) pefree(Z_PTR_P(v), 1); } -ZEND_API zend_internal_attribute *zend_internal_attribute_register(zend_class_entry *ce, uint32_t flags) +ZEND_API zend_internal_attribute *zend_mark_internal_attribute(zend_class_entry *ce) { zend_internal_attribute *internal_attr; + zend_attribute *attr; if (ce->type != ZEND_INTERNAL_CLASS) { zend_error_noreturn(E_ERROR, "Only internal classes can be registered as compiler attribute"); } - internal_attr = pemalloc(sizeof(zend_internal_attribute), 1); - internal_attr->ce = ce; - internal_attr->flags = flags; - internal_attr->validator = NULL; + ZEND_HASH_FOREACH_PTR(ce->attributes, attr) { + if (zend_string_equals(attr->name, zend_ce_attribute->name)) { + internal_attr = pemalloc(sizeof(zend_internal_attribute), 1); + internal_attr->ce = ce; + internal_attr->flags = Z_LVAL(attr->args[0].value); + internal_attr->validator = NULL; - zend_string *lcname = zend_string_tolower_ex(ce->name, 1); + zend_string *lcname = zend_string_tolower_ex(ce->name, 1); + zend_hash_update_ptr(&internal_attributes, lcname, internal_attr); + zend_string_release(lcname); - zend_hash_update_ptr(&internal_attributes, lcname, internal_attr); + return internal_attr; + } + } ZEND_HASH_FOREACH_END(); + + zend_error_noreturn(E_ERROR, "Classes must be first marked as attribute before being able to be registered as internal attribute class"); +} + +ZEND_API zend_internal_attribute *zend_internal_attribute_register(zend_class_entry *ce, uint32_t flags) +{ zend_attribute *attr = zend_add_class_attribute(ce, zend_ce_attribute->name, 1); ZVAL_LONG(&attr->args[0].value, flags); - zend_string_release(lcname); - return internal_attr; + return zend_mark_internal_attribute(ce); } ZEND_API zend_internal_attribute *zend_internal_attribute_get(zend_string *lcname) @@ -352,32 +364,23 @@ void zend_register_attribute_ce(void) zend_hash_init(&internal_attributes, 8, NULL, free_internal_attribute, 1); zend_ce_attribute = register_class_Attribute(); - attr = zend_internal_attribute_register(zend_ce_attribute, ZEND_ATTRIBUTE_TARGET_CLASS); + attr = zend_mark_internal_attribute(zend_ce_attribute); attr->validator = validate_attribute; - zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_CLASS"), ZEND_ATTRIBUTE_TARGET_CLASS); - zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_FUNCTION"), ZEND_ATTRIBUTE_TARGET_FUNCTION); - zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_METHOD"), ZEND_ATTRIBUTE_TARGET_METHOD); - zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_PROPERTY"), ZEND_ATTRIBUTE_TARGET_PROPERTY); - zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_CLASS_CONSTANT"), ZEND_ATTRIBUTE_TARGET_CLASS_CONST); - zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_PARAMETER"), ZEND_ATTRIBUTE_TARGET_PARAMETER); - zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_ALL"), ZEND_ATTRIBUTE_TARGET_ALL); - zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("IS_REPEATABLE"), ZEND_ATTRIBUTE_IS_REPEATABLE); - zend_ce_return_type_will_change_attribute = register_class_ReturnTypeWillChange(); - zend_internal_attribute_register(zend_ce_return_type_will_change_attribute, ZEND_ATTRIBUTE_TARGET_METHOD); + zend_mark_internal_attribute(zend_ce_return_type_will_change_attribute); zend_ce_allow_dynamic_properties = register_class_AllowDynamicProperties(); - attr = zend_internal_attribute_register(zend_ce_allow_dynamic_properties, ZEND_ATTRIBUTE_TARGET_CLASS); + attr = zend_mark_internal_attribute(zend_ce_allow_dynamic_properties); attr->validator = validate_allow_dynamic_properties; zend_ce_sensitive_parameter = register_class_SensitiveParameter(); - attr = zend_internal_attribute_register(zend_ce_sensitive_parameter, ZEND_ATTRIBUTE_TARGET_PARAMETER); + zend_mark_internal_attribute(zend_ce_sensitive_parameter); memcpy(&attributes_object_handlers_sensitive_parameter_value, &std_object_handlers, sizeof(zend_object_handlers)); attributes_object_handlers_sensitive_parameter_value.get_properties_for = attributes_sensitive_parameter_value_get_properties_for; - /* This is not an actual attribute, thus the zend_internal_attribute_register() call is missing. */ + /* This is not an actual attribute, thus the zend_mark_internal_attribute() call is missing. */ zend_ce_sensitive_parameter_value = register_class_SensitiveParameterValue(); zend_ce_sensitive_parameter_value->create_object = attributes_sensitive_parameter_value_new; } diff --git a/Zend/zend_attributes.h b/Zend/zend_attributes.h index 6ffd3d89f94a0..52888ebcf7aa1 100644 --- a/Zend/zend_attributes.h +++ b/Zend/zend_attributes.h @@ -77,6 +77,7 @@ ZEND_API zend_result zend_get_attribute_value(zval *ret, zend_attribute *attr, u ZEND_API zend_string *zend_get_attribute_target_names(uint32_t targets); ZEND_API bool zend_is_attribute_repeated(HashTable *attributes, zend_attribute *attr); +ZEND_API zend_internal_attribute *zend_mark_internal_attribute(zend_class_entry *ce); ZEND_API zend_internal_attribute *zend_internal_attribute_register(zend_class_entry *ce, uint32_t flags); ZEND_API zend_internal_attribute *zend_internal_attribute_get(zend_string *lcname); diff --git a/Zend/zend_attributes.stub.php b/Zend/zend_attributes.stub.php index 842ed9229cd6e..34056404b3aca 100644 --- a/Zend/zend_attributes.stub.php +++ b/Zend/zend_attributes.stub.php @@ -2,18 +2,62 @@ /** @generate-class-entries */ +#[Attribute(Attribute::TARGET_CLASS)] final class Attribute { + /** + * @var int + * @cname ZEND_ATTRIBUTE_TARGET_CLASS + */ + const TARGET_CLASS = UNKNOWN; + /** + * @var int + * @cname ZEND_ATTRIBUTE_TARGET_FUNCTION + */ + const TARGET_FUNCTION = UNKNOWN; + /** + * @var int + * @cname ZEND_ATTRIBUTE_TARGET_METHOD + */ + const TARGET_METHOD = UNKNOWN; + /** + * @var int + * @cname ZEND_ATTRIBUTE_TARGET_PROPERTY + */ + const TARGET_PROPERTY = UNKNOWN; + /** + * @var int + * @cname ZEND_ATTRIBUTE_TARGET_CLASS_CONST + */ + const TARGET_CLASS_CONSTANT = UNKNOWN; + /** + * @var int + * @cname ZEND_ATTRIBUTE_TARGET_PARAMETER + */ + const TARGET_PARAMETER = UNKNOWN; + /** + * @var int + * @cname ZEND_ATTRIBUTE_TARGET_ALL + */ + const TARGET_ALL = UNKNOWN; + /** + * @var int + * @cname ZEND_ATTRIBUTE_IS_REPEATABLE + */ + const IS_REPEATABLE = UNKNOWN; + public int $flags; public function __construct(int $flags = Attribute::TARGET_ALL) {} } +#[Attribute(Attribute::TARGET_METHOD)] final class ReturnTypeWillChange { public function __construct() {} } +#[Attribute(Attribute::TARGET_CLASS)] final class AllowDynamicProperties { public function __construct() {} @@ -22,6 +66,7 @@ public function __construct() {} /** * @strict-properties */ +#[Attribute(Attribute::TARGET_PARAMETER)] final class SensitiveParameter { public function __construct() {} diff --git a/Zend/zend_attributes_arginfo.h b/Zend/zend_attributes_arginfo.h index 7c624949bf24b..4311b12d4afb4 100644 --- a/Zend/zend_attributes_arginfo.h +++ b/Zend/zend_attributes_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 5d9a092c1f0da5f32d9a161cc5166ed794ffe8e9 */ + * Stub hash: a07e5020fd36cda191c1f3b4fca180157bd74cbc */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Attribute___construct, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "Attribute::TARGET_ALL") @@ -71,12 +71,67 @@ static zend_class_entry *register_class_Attribute(void) class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; + zval const_TARGET_CLASS_value; + ZVAL_LONG(&const_TARGET_CLASS_value, ZEND_ATTRIBUTE_TARGET_CLASS); + zend_string *const_TARGET_CLASS_name = zend_string_init_interned("TARGET_CLASS", sizeof("TARGET_CLASS") - 1, 1); + zend_declare_class_constant_ex(class_entry, const_TARGET_CLASS_name, &const_TARGET_CLASS_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(const_TARGET_CLASS_name); + + zval const_TARGET_FUNCTION_value; + ZVAL_LONG(&const_TARGET_FUNCTION_value, ZEND_ATTRIBUTE_TARGET_FUNCTION); + zend_string *const_TARGET_FUNCTION_name = zend_string_init_interned("TARGET_FUNCTION", sizeof("TARGET_FUNCTION") - 1, 1); + zend_declare_class_constant_ex(class_entry, const_TARGET_FUNCTION_name, &const_TARGET_FUNCTION_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(const_TARGET_FUNCTION_name); + + zval const_TARGET_METHOD_value; + ZVAL_LONG(&const_TARGET_METHOD_value, ZEND_ATTRIBUTE_TARGET_METHOD); + zend_string *const_TARGET_METHOD_name = zend_string_init_interned("TARGET_METHOD", sizeof("TARGET_METHOD") - 1, 1); + zend_declare_class_constant_ex(class_entry, const_TARGET_METHOD_name, &const_TARGET_METHOD_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(const_TARGET_METHOD_name); + + zval const_TARGET_PROPERTY_value; + ZVAL_LONG(&const_TARGET_PROPERTY_value, ZEND_ATTRIBUTE_TARGET_PROPERTY); + zend_string *const_TARGET_PROPERTY_name = zend_string_init_interned("TARGET_PROPERTY", sizeof("TARGET_PROPERTY") - 1, 1); + zend_declare_class_constant_ex(class_entry, const_TARGET_PROPERTY_name, &const_TARGET_PROPERTY_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(const_TARGET_PROPERTY_name); + + zval const_TARGET_CLASS_CONSTANT_value; + ZVAL_LONG(&const_TARGET_CLASS_CONSTANT_value, ZEND_ATTRIBUTE_TARGET_CLASS_CONST); + zend_string *const_TARGET_CLASS_CONSTANT_name = zend_string_init_interned("TARGET_CLASS_CONSTANT", sizeof("TARGET_CLASS_CONSTANT") - 1, 1); + zend_declare_class_constant_ex(class_entry, const_TARGET_CLASS_CONSTANT_name, &const_TARGET_CLASS_CONSTANT_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(const_TARGET_CLASS_CONSTANT_name); + + zval const_TARGET_PARAMETER_value; + ZVAL_LONG(&const_TARGET_PARAMETER_value, ZEND_ATTRIBUTE_TARGET_PARAMETER); + zend_string *const_TARGET_PARAMETER_name = zend_string_init_interned("TARGET_PARAMETER", sizeof("TARGET_PARAMETER") - 1, 1); + zend_declare_class_constant_ex(class_entry, const_TARGET_PARAMETER_name, &const_TARGET_PARAMETER_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(const_TARGET_PARAMETER_name); + + zval const_TARGET_ALL_value; + ZVAL_LONG(&const_TARGET_ALL_value, ZEND_ATTRIBUTE_TARGET_ALL); + zend_string *const_TARGET_ALL_name = zend_string_init_interned("TARGET_ALL", sizeof("TARGET_ALL") - 1, 1); + zend_declare_class_constant_ex(class_entry, const_TARGET_ALL_name, &const_TARGET_ALL_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(const_TARGET_ALL_name); + + zval const_IS_REPEATABLE_value; + ZVAL_LONG(&const_IS_REPEATABLE_value, ZEND_ATTRIBUTE_IS_REPEATABLE); + zend_string *const_IS_REPEATABLE_name = zend_string_init_interned("IS_REPEATABLE", sizeof("IS_REPEATABLE") - 1, 1); + zend_declare_class_constant_ex(class_entry, const_IS_REPEATABLE_name, &const_IS_REPEATABLE_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(const_IS_REPEATABLE_name); + zval property_flags_default_value; ZVAL_UNDEF(&property_flags_default_value); zend_string *property_flags_name = zend_string_init("flags", sizeof("flags") - 1, 1); zend_declare_typed_property(class_entry, property_flags_name, &property_flags_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(property_flags_name); + zend_string *attribute_name_Attribute_class_Attribute = zend_string_init("Attribute", sizeof("Attribute") - 1, 1); + zend_attribute *attribute_Attribute_class_Attribute = zend_add_class_attribute(class_entry, attribute_name_Attribute_class_Attribute, 1); + zend_string_release(attribute_name_Attribute_class_Attribute); + zval attribute_Attribute_class_Attribute_arg0; + ZVAL_LONG(&attribute_Attribute_class_Attribute_arg0, ZEND_ATTRIBUTE_TARGET_CLASS); + ZVAL_COPY_VALUE(&attribute_Attribute_class_Attribute->args[0].value, &attribute_Attribute_class_Attribute_arg0); + return class_entry; } @@ -88,6 +143,13 @@ static zend_class_entry *register_class_ReturnTypeWillChange(void) class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; + zend_string *attribute_name_Attribute_class_ReturnTypeWillChange = zend_string_init("Attribute", sizeof("Attribute") - 1, 1); + zend_attribute *attribute_Attribute_class_ReturnTypeWillChange = zend_add_class_attribute(class_entry, attribute_name_Attribute_class_ReturnTypeWillChange, 1); + zend_string_release(attribute_name_Attribute_class_ReturnTypeWillChange); + zval attribute_Attribute_class_ReturnTypeWillChange_arg0; + ZVAL_LONG(&attribute_Attribute_class_ReturnTypeWillChange_arg0, ZEND_ATTRIBUTE_TARGET_METHOD); + ZVAL_COPY_VALUE(&attribute_Attribute_class_ReturnTypeWillChange->args[0].value, &attribute_Attribute_class_ReturnTypeWillChange_arg0); + return class_entry; } @@ -99,6 +161,13 @@ static zend_class_entry *register_class_AllowDynamicProperties(void) class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; + zend_string *attribute_name_Attribute_class_AllowDynamicProperties = zend_string_init("Attribute", sizeof("Attribute") - 1, 1); + zend_attribute *attribute_Attribute_class_AllowDynamicProperties = zend_add_class_attribute(class_entry, attribute_name_Attribute_class_AllowDynamicProperties, 1); + zend_string_release(attribute_name_Attribute_class_AllowDynamicProperties); + zval attribute_Attribute_class_AllowDynamicProperties_arg0; + ZVAL_LONG(&attribute_Attribute_class_AllowDynamicProperties_arg0, ZEND_ATTRIBUTE_TARGET_CLASS); + ZVAL_COPY_VALUE(&attribute_Attribute_class_AllowDynamicProperties->args[0].value, &attribute_Attribute_class_AllowDynamicProperties_arg0); + return class_entry; } @@ -110,6 +179,13 @@ static zend_class_entry *register_class_SensitiveParameter(void) class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES; + zend_string *attribute_name_Attribute_class_SensitiveParameter = zend_string_init("Attribute", sizeof("Attribute") - 1, 1); + zend_attribute *attribute_Attribute_class_SensitiveParameter = zend_add_class_attribute(class_entry, attribute_name_Attribute_class_SensitiveParameter, 1); + zend_string_release(attribute_name_Attribute_class_SensitiveParameter); + zval attribute_Attribute_class_SensitiveParameter_arg0; + ZVAL_LONG(&attribute_Attribute_class_SensitiveParameter_arg0, ZEND_ATTRIBUTE_TARGET_PARAMETER); + ZVAL_COPY_VALUE(&attribute_Attribute_class_SensitiveParameter->args[0].value, &attribute_Attribute_class_SensitiveParameter_arg0); + return class_entry; } diff --git a/Zend/zend_builtin_functions_arginfo.h b/Zend/zend_builtin_functions_arginfo.h index 1dbc4255945a6..abcbfaaa9e776 100644 --- a/Zend/zend_builtin_functions_arginfo.h +++ b/Zend/zend_builtin_functions_arginfo.h @@ -354,7 +354,10 @@ 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); + + zend_string *attribute_name_AllowDynamicProperties_class_stdClass = zend_string_init("AllowDynamicProperties", sizeof("AllowDynamicProperties") - 1, 1); + zend_add_class_attribute(class_entry, attribute_name_AllowDynamicProperties_class_stdClass, 0); + zend_string_release(attribute_name_AllowDynamicProperties_class_stdClass); return class_entry; } diff --git a/build/gen_stub.php b/build/gen_stub.php index 202ab1fdc6ed4..c712be21e8c78 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -46,28 +46,54 @@ function processDirectory(string $dir, Context $context): array { return $fileInfos; } -function processStubFile(string $stubFile, Context $context): ?FileInfo { +function processStubFile(string $stubFile, Context $context, bool $includeOnly = false): ?FileInfo { try { if (!file_exists($stubFile)) { throw new Exception("File $stubFile does not exist"); } - $stubFilenameWithoutExtension = str_replace(".stub.php", "", $stubFile); - $arginfoFile = "{$stubFilenameWithoutExtension}_arginfo.h"; - $legacyFile = "{$stubFilenameWithoutExtension}_legacy_arginfo.h"; + if (!$includeOnly) { + $stubFilenameWithoutExtension = str_replace(".stub.php", "", $stubFile); + $arginfoFile = "{$stubFilenameWithoutExtension}_arginfo.h"; + $legacyFile = "{$stubFilenameWithoutExtension}_legacy_arginfo.h"; - $stubCode = file_get_contents($stubFile); - $stubHash = computeStubHash($stubCode); - $oldStubHash = extractStubHash($arginfoFile); - if ($stubHash === $oldStubHash && !$context->forceParse) { - /* Stub file did not change, do not regenerate. */ - return null; + $stubCode = file_get_contents($stubFile); + $stubHash = computeStubHash($stubCode); + $oldStubHash = extractStubHash($arginfoFile); + if ($stubHash === $oldStubHash && !$context->forceParse) { + /* Stub file did not change, do not regenerate. */ + return null; + } } - initPhpParser(); - $fileInfo = parseStubFile($stubCode); - $constInfos = $fileInfo->getAllConstInfos(); - $context->allConstInfos = array_merge($context->allConstInfos, $constInfos); + if (!$fileInfo = $context->parsedFiles[$stubFile] ?? null) { + initPhpParser(); + $fileInfo = parseStubFile($stubCode ?? file_get_contents($stubFile)); + $context->parsedFiles[$stubFile] = $fileInfo; + + foreach ($fileInfo->dependencies as $dependency) { + // TODO add header search path for extensions? + $prefixes = [dirname($stubFile) . "/", dirname(__DIR__) . "/"]; + foreach ($prefixes as $prefix) { + $depFile = $prefix . $dependency; + if (file_exists($depFile)) { + break; + } + $depFile = null; + } + if (!$depFile) { + throw new Exception("File $stubFile includes a file $dependency which does not exist"); + } + processStubFile($depFile, $context, true); + } + + $constInfos = $fileInfo->getAllConstInfos(); + $context->allConstInfos = array_merge($context->allConstInfos, $constInfos); + } + + if ($includeOnly) { + return $fileInfo; + } $arginfoCode = generateArgInfoCode( basename($stubFilenameWithoutExtension), @@ -131,6 +157,8 @@ class Context { public $forceRegeneration = false; /** @var iterable */ public iterable $allConstInfos = []; + /** @var FileInfo[] */ + public array $parsedFiles = []; } class ArrayType extends SimpleType { @@ -2257,6 +2285,38 @@ public function getDeclaration(iterable $allConstInfos): string { } } +class AttributeInfo { + /** @var string */ + public $class; + /** @var \PhpParser\Node\Arg[] */ + public $args; + + /** @param \PhpParser\Node\Arg[] $args */ + public function __construct(string $class, array $args) { + $this->class = $class; + $this->args = $args; + } + + /** @param iterable $allConstInfos */ + public function generateCode(string $invocation, string $nameSuffix, iterable $allConstInfos): string { + $code = "\n"; + $escapedAttributeName = strtr($this->class, '\\', '_'); + $code .= "\tzend_string *attribute_name_{$escapedAttributeName}_$nameSuffix = zend_string_init(\"" . addcslashes($this->class, "\\") . "\", sizeof(\"" . addcslashes($this->class, "\\") . "\") - 1, 1);\n"; + $code .= "\t" . ($this->args ? "zend_attribute *attribute_{$escapedAttributeName}_$nameSuffix = " : "") . "$invocation, attribute_name_{$escapedAttributeName}_$nameSuffix, " . count($this->args) . ");\n"; + $code .= "\tzend_string_release(attribute_name_{$escapedAttributeName}_$nameSuffix);\n"; + foreach ($this->args as $i => $arg) { + $value = EvaluatedValue::createFromExpression($arg->value, null, null, $allConstInfos); + $zvalName = "attribute_{$escapedAttributeName}_{$nameSuffix}_arg$i"; + $code .= $value->initializeZval($zvalName, $allConstInfos); + $code .= "\tZVAL_COPY_VALUE(&attribute_{$escapedAttributeName}_{$nameSuffix}->args[$i].value, &$zvalName);\n"; + if ($arg->name) { + $code .= "\tattribute_{$escapedAttributeName}_{$nameSuffix}->args[$i].name = zend_string_init(\"{$arg->name->name}\", sizeof(\"{$arg->name->name}\") - 1, 1);\n"; + } + } + return $code; + } +} + class ClassInfo { /** @var Name */ public $name; @@ -2272,8 +2332,8 @@ class ClassInfo { public $isDeprecated; /** @var bool */ public $isStrictProperties; - /** @var bool */ - public $allowsDynamicProperties; + /** @var AttributeInfo[] */ + public $attributes; /** @var bool */ public $isNotSerializable; /** @var Name[] */ @@ -2292,6 +2352,7 @@ class ClassInfo { public $cond; /** + * @param AttributeInfo[] $attributes * @param Name[] $extends * @param Name[] $implements * @param ConstInfo[] $constInfos @@ -2307,7 +2368,7 @@ public function __construct( ?SimpleType $enumBackingType, bool $isDeprecated, bool $isStrictProperties, - bool $allowsDynamicProperties, + array $attributes, bool $isNotSerializable, array $extends, array $implements, @@ -2324,7 +2385,7 @@ public function __construct( $this->enumBackingType = $enumBackingType; $this->isDeprecated = $isDeprecated; $this->isStrictProperties = $isStrictProperties; - $this->allowsDynamicProperties = $allowsDynamicProperties; + $this->attributes = $attributes; $this->isNotSerializable = $isNotSerializable; $this->extends = $extends; $this->implements = $implements; @@ -2413,8 +2474,8 @@ function (Name $item) { $code .= $property->getDeclaration($allConstInfos); } - if ($this->allowsDynamicProperties) { - $code .= "\tzend_add_class_attribute(class_entry, zend_ce_allow_dynamic_properties->name, 0);\n"; + foreach ($this->attributes as $attribute) { + $code .= $attribute->generateCode("zend_add_class_attribute(class_entry", "class_$escapedName", $allConstInfos); } if ($attributeInitializationCode = generateAttributeInitialization($this->funcInfos, $this->cond)) { @@ -2460,8 +2521,10 @@ private function getFlagsAsString(): string $flags[] = "ZEND_ACC_NO_DYNAMIC_PROPERTIES"; } - if ($this->allowsDynamicProperties) { - $flags[] = "ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES"; + foreach ($this->attributes as $attr) { + if ($attr->class === "AllowDynamicProperties") { + $flags[] = "ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES"; + } } if ($this->isNotSerializable) { @@ -2861,6 +2924,8 @@ private function appendInheritedMemberSectionToClassSynopsis(DOMDocument $doc, D } class FileInfo { + /** @var string[] */ + public $dependencies = []; /** @var ConstInfo[] */ public $constInfos = []; /** @var FuncInfo[] */ @@ -3286,6 +3351,7 @@ function parseClass( $isStrictProperties = false; $isNotSerializable = false; $allowsDynamicProperties = false; + $attributes = []; if ($comment) { $tags = parseDocComment($comment); @@ -3304,12 +3370,11 @@ function parseClass( foreach ($class->attrGroups as $attrGroup) { foreach ($attrGroup->attrs as $attr) { - switch ($attr->name->toCodeString()) { - case '\\AllowDynamicProperties': + $attributes[] = new AttributeInfo($attr->name->toString(), $attr->args); + switch ($attr->name->toString()) { + case 'AllowDynamicProperties': $allowsDynamicProperties = true; break; - default: - throw new Exception("Unhandled attribute {$attr->name->toCodeString()}."); } } } @@ -3348,7 +3413,7 @@ function parseClass( ? SimpleType::fromNode($class->scalarType) : null, $isDeprecated, $isStrictProperties, - $allowsDynamicProperties, + $attributes, $isNotSerializable, $extends, $implements, @@ -3511,6 +3576,14 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac continue; } + if ($stmt instanceof Stmt\Expression) { + $expr = $stmt->expr; + if ($expr instanceof Expr\Include_) { + $fileInfo->dependencies[] = (string)EvaluatedValue::createFromExpression($expr->expr, null, null, [])->value; + continue; + } + } + throw new Exception("Unexpected node {$stmt->getType()}"); } } diff --git a/ext/oci8/oci8_arginfo.h b/ext/oci8/oci8_arginfo.h index eff5d7c0eee3b..ba49c7a185138 100644 --- a/ext/oci8/oci8_arginfo.h +++ b/ext/oci8/oci8_arginfo.h @@ -816,7 +816,10 @@ static zend_class_entry *register_class_OCILob(void) INIT_CLASS_ENTRY(ce, "OCILob", class_OCILob_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); + + zend_string *attribute_name_AllowDynamicProperties_class_OCILob = zend_string_init("AllowDynamicProperties", sizeof("AllowDynamicProperties") - 1, 1); + zend_add_class_attribute(class_entry, attribute_name_AllowDynamicProperties_class_OCILob, 0); + zend_string_release(attribute_name_AllowDynamicProperties_class_OCILob); return class_entry; } @@ -828,7 +831,10 @@ static zend_class_entry *register_class_OCICollection(void) INIT_CLASS_ENTRY(ce, "OCICollection", class_OCICollection_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); + + zend_string *attribute_name_AllowDynamicProperties_class_OCICollection = zend_string_init("AllowDynamicProperties", sizeof("AllowDynamicProperties") - 1, 1); + zend_add_class_attribute(class_entry, attribute_name_AllowDynamicProperties_class_OCICollection, 0); + zend_string_release(attribute_name_AllowDynamicProperties_class_OCICollection); return class_entry; } diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 33a0e62e505dc..14dcfef98f5ad 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -634,12 +634,12 @@ PHP_MINIT_FUNCTION(zend_test) zend_test_attribute = register_class_ZendTestAttribute(); { - zend_internal_attribute *attr = zend_internal_attribute_register(zend_test_attribute, ZEND_ATTRIBUTE_TARGET_ALL); + zend_internal_attribute *attr = zend_mark_internal_attribute(zend_test_attribute); attr->validator = zend_attribute_validate_zendtestattribute; } zend_test_parameter_attribute = register_class_ZendTestParameterAttribute(); - zend_internal_attribute_register(zend_test_parameter_attribute, ZEND_ATTRIBUTE_TARGET_PARAMETER); + zend_mark_internal_attribute(zend_test_parameter_attribute); { zend_attribute *attr; diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index 13b2fd346e7b1..b99a28ea82501 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -4,6 +4,8 @@ namespace { + require "Zend/zend_attributes.stub.php"; + interface _ZendTestInterface { } @@ -41,10 +43,12 @@ trait _ZendTestTrait { public function testMethod(): bool {} } + #[Attribute(Attribute::TARGET_ALL)] final class ZendTestAttribute { } + #[Attribute(Attribute::TARGET_PARAMETER)] final class ZendTestParameterAttribute { public string $parameter; diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index 8c8e67d26954a..3e37426913ad4 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 1a23b7473e5b4525352445545c6b3ab374c4e949 */ + * Stub hash: 3ad8ef04d52f1a099d9fd3b6c2c02b90de2980be */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -391,6 +391,13 @@ static zend_class_entry *register_class_ZendTestAttribute(void) class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; + zend_string *attribute_name_Attribute_class_ZendTestAttribute = zend_string_init("Attribute", sizeof("Attribute") - 1, 1); + zend_attribute *attribute_Attribute_class_ZendTestAttribute = zend_add_class_attribute(class_entry, attribute_name_Attribute_class_ZendTestAttribute, 1); + zend_string_release(attribute_name_Attribute_class_ZendTestAttribute); + zval attribute_Attribute_class_ZendTestAttribute_arg0; + ZVAL_LONG(&attribute_Attribute_class_ZendTestAttribute_arg0, ZEND_ATTRIBUTE_TARGET_ALL); + ZVAL_COPY_VALUE(&attribute_Attribute_class_ZendTestAttribute->args[0].value, &attribute_Attribute_class_ZendTestAttribute_arg0); + return class_entry; } @@ -408,6 +415,13 @@ static zend_class_entry *register_class_ZendTestParameterAttribute(void) zend_declare_typed_property(class_entry, property_parameter_name, &property_parameter_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); zend_string_release(property_parameter_name); + zend_string *attribute_name_Attribute_class_ZendTestParameterAttribute = zend_string_init("Attribute", sizeof("Attribute") - 1, 1); + zend_attribute *attribute_Attribute_class_ZendTestParameterAttribute = zend_add_class_attribute(class_entry, attribute_name_Attribute_class_ZendTestParameterAttribute, 1); + zend_string_release(attribute_name_Attribute_class_ZendTestParameterAttribute); + zval attribute_Attribute_class_ZendTestParameterAttribute_arg0; + ZVAL_LONG(&attribute_Attribute_class_ZendTestParameterAttribute_arg0, ZEND_ATTRIBUTE_TARGET_PARAMETER); + ZVAL_COPY_VALUE(&attribute_Attribute_class_ZendTestParameterAttribute->args[0].value, &attribute_Attribute_class_ZendTestParameterAttribute_arg0); + return class_entry; }