diff --git a/build/gen_stub.php b/build/gen_stub.php index b17fbda6bf12b..4efe0164c40e8 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -3124,7 +3124,7 @@ public function generateCode(string $invocation, string $nameSuffix, array $allC $code .= $value->initializeZval($zvalName); $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"; + $code .= "\tattribute_{$escapedAttributeName}_{$nameSuffix}->args[$i].name = zend_string_init_interned(\"{$arg->name->name}\", sizeof(\"{$arg->name->name}\") - 1, 1);\n"; } } return $code; diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 78adc05ccca5e..e1ffb36cbe4f2 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -58,6 +58,7 @@ static zend_class_entry *zend_test_attribute; static zend_class_entry *zend_test_repeatable_attribute; static zend_class_entry *zend_test_parameter_attribute; static zend_class_entry *zend_test_property_attribute; +static zend_class_entry *zend_test_attribute_with_arguments; static zend_class_entry *zend_test_class_with_method_with_parameter_attribute; static zend_class_entry *zend_test_child_class_with_method_with_parameter_attribute; static zend_class_entry *zend_test_class_with_property_attribute; @@ -575,6 +576,11 @@ static ZEND_FUNCTION(zend_test_parameter_with_attribute) RETURN_LONG(1); } +static ZEND_FUNCTION(zend_test_attribute_with_named_argument) +{ + ZEND_PARSE_PARAMETERS_NONE(); +} + #ifdef ZEND_CHECK_STACK_LIMIT static ZEND_FUNCTION(zend_test_zend_call_stack_get) { @@ -989,6 +995,19 @@ static ZEND_METHOD(ZendTestPropertyAttribute, __construct) ZVAL_STR_COPY(OBJ_PROP_NUM(Z_OBJ_P(ZEND_THIS), 0), parameter); } +static ZEND_METHOD(ZendTestAttributeWithArguments, __construct) +{ + zval *arg; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(arg) + ZEND_PARSE_PARAMETERS_END(); + + zend_string *property_name = zend_string_init("arg", strlen("arg"), 0); + zend_update_property_ex(zend_test_attribute_with_arguments, Z_OBJ_P(ZEND_THIS), property_name, arg); + zend_string_release(property_name); +} + static ZEND_METHOD(ZendTestClassWithMethodWithParameterAttribute, no_override) { zend_string *parameter; @@ -1217,6 +1236,9 @@ PHP_MINIT_FUNCTION(zend_test) zend_test_property_attribute = register_class_ZendTestPropertyAttribute(); zend_mark_internal_attribute(zend_test_property_attribute); + zend_test_attribute_with_arguments = register_class_ZendTestAttributeWithArguments(); + zend_mark_internal_attribute(zend_test_attribute_with_arguments); + zend_test_class_with_method_with_parameter_attribute = register_class_ZendTestClassWithMethodWithParameterAttribute(); zend_test_child_class_with_method_with_parameter_attribute = register_class_ZendTestChildClassWithMethodWithParameterAttribute(zend_test_class_with_method_with_parameter_attribute); diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index b7790a256e48e..3a888fef6897a 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -104,6 +104,13 @@ public function testMethod(): bool {} final class ZendTestAttribute { } + #[Attribute(Attribute::TARGET_ALL)] + final class ZendTestAttributeWithArguments { + public readonly mixed $arg; + + public function __construct(mixed $arg) {} + } + #[Attribute(Attribute::TARGET_ALL|Attribute::IS_REPEATABLE)] final class ZendTestRepeatableAttribute { } @@ -243,6 +250,9 @@ function zend_test_parameter_with_attribute( string $parameter ): int {} + #[ZendTestAttributeWithArguments(arg: "foo")] + function zend_test_attribute_with_named_argument(): void {} + function zend_get_current_func_name(): string {} function zend_call_method(object|string $obj_or_class, string $method, mixed $arg1 = UNKNOWN, mixed $arg2 = UNKNOWN): mixed {} diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index 0bd79a13cf7b5..d78e42a92e005 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: 810a94e09724a27d46c99495593da999cfc46243 */ + * Stub hash: b7e8a9c27def16e8691883bea7837def1f717ab8 */ ZEND_STATIC_ASSERT(PHP_VERSION_ID >= 80000, "test_arginfo.h only supports PHP version ID 80000 or newer, " "but it is included on an older PHP version"); @@ -90,6 +90,8 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_parameter_with_attribu ZEND_ARG_TYPE_INFO(0, parameter, IS_STRING, 0) ZEND_END_ARG_INFO() +#define arginfo_zend_test_attribute_with_named_argument arginfo_zend_test_void_return + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_get_current_func_name, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() @@ -208,6 +210,10 @@ ZEND_END_ARG_INFO() #define arginfo_class__ZendTestTrait_testMethod arginfo_zend_test_is_pcre_bundled +ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ZendTestAttributeWithArguments___construct, 0, 0, 1) + ZEND_ARG_TYPE_INFO(0, arg, IS_MIXED, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ZendTestParameterAttribute___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, parameter, IS_STRING, 0) ZEND_END_ARG_INFO() @@ -262,6 +268,7 @@ static ZEND_FUNCTION(zend_weakmap_remove); static ZEND_FUNCTION(zend_weakmap_dump); static ZEND_FUNCTION(zend_get_unit_enum); static ZEND_FUNCTION(zend_test_parameter_with_attribute); +static ZEND_FUNCTION(zend_test_attribute_with_named_argument); static ZEND_FUNCTION(zend_get_current_func_name); static ZEND_FUNCTION(zend_call_method); static ZEND_FUNCTION(zend_object_init_with_constructor); @@ -302,6 +309,7 @@ static ZEND_METHOD(_ZendTestMagicCall, __call); static ZEND_METHOD(_ZendTestChildClass, returnsThrowable); static ZEND_METHOD(ZendAttributeTest, testMethod); static ZEND_METHOD(_ZendTestTrait, testMethod); +static ZEND_METHOD(ZendTestAttributeWithArguments, __construct); static ZEND_METHOD(ZendTestParameterAttribute, __construct); static ZEND_METHOD(ZendTestPropertyAttribute, __construct); static ZEND_METHOD(ZendTestClassWithMethodWithParameterAttribute, no_override); @@ -359,6 +367,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(zend_weakmap_dump, arginfo_zend_weakmap_dump) ZEND_FE(zend_get_unit_enum, arginfo_zend_get_unit_enum) ZEND_FE(zend_test_parameter_with_attribute, arginfo_zend_test_parameter_with_attribute) + ZEND_FE(zend_test_attribute_with_named_argument, arginfo_zend_test_attribute_with_named_argument) ZEND_FE(zend_get_current_func_name, arginfo_zend_get_current_func_name) ZEND_FE(zend_call_method, arginfo_zend_call_method) ZEND_FE(zend_object_init_with_constructor, arginfo_zend_object_init_with_constructor) @@ -466,6 +475,11 @@ static const zend_function_entry class_ZendTestAttribute_methods[] = { ZEND_FE_END }; +static const zend_function_entry class_ZendTestAttributeWithArguments_methods[] = { + ZEND_ME(ZendTestAttributeWithArguments, __construct, arginfo_class_ZendTestAttributeWithArguments___construct, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; + static const zend_function_entry class_ZendTestRepeatableAttribute_methods[] = { ZEND_FE_END }; @@ -553,6 +567,15 @@ static void register_test_symbols(int module_number) zend_string *attribute_ZendTestParameterAttribute_func_zend_test_parameter_with_attribute_arg0_0_arg0_str = zend_string_init("value1", strlen("value1"), 1); ZVAL_STR(&attribute_ZendTestParameterAttribute_func_zend_test_parameter_with_attribute_arg0_0_arg0, attribute_ZendTestParameterAttribute_func_zend_test_parameter_with_attribute_arg0_0_arg0_str); ZVAL_COPY_VALUE(&attribute_ZendTestParameterAttribute_func_zend_test_parameter_with_attribute_arg0_0->args[0].value, &attribute_ZendTestParameterAttribute_func_zend_test_parameter_with_attribute_arg0_0_arg0); + + zend_string *attribute_name_ZendTestAttributeWithArguments_func_zend_test_attribute_with_named_argument_0 = zend_string_init_interned("ZendTestAttributeWithArguments", sizeof("ZendTestAttributeWithArguments") - 1, 1); + zend_attribute *attribute_ZendTestAttributeWithArguments_func_zend_test_attribute_with_named_argument_0 = zend_add_function_attribute(zend_hash_str_find_ptr(CG(function_table), "zend_test_attribute_with_named_argument", sizeof("zend_test_attribute_with_named_argument") - 1), attribute_name_ZendTestAttributeWithArguments_func_zend_test_attribute_with_named_argument_0, 1); + zend_string_release(attribute_name_ZendTestAttributeWithArguments_func_zend_test_attribute_with_named_argument_0); + zval attribute_ZendTestAttributeWithArguments_func_zend_test_attribute_with_named_argument_0_arg0; + zend_string *attribute_ZendTestAttributeWithArguments_func_zend_test_attribute_with_named_argument_0_arg0_str = zend_string_init("foo", strlen("foo"), 1); + ZVAL_STR(&attribute_ZendTestAttributeWithArguments_func_zend_test_attribute_with_named_argument_0_arg0, attribute_ZendTestAttributeWithArguments_func_zend_test_attribute_with_named_argument_0_arg0_str); + ZVAL_COPY_VALUE(&attribute_ZendTestAttributeWithArguments_func_zend_test_attribute_with_named_argument_0->args[0].value, &attribute_ZendTestAttributeWithArguments_func_zend_test_attribute_with_named_argument_0_arg0); + attribute_ZendTestAttributeWithArguments_func_zend_test_attribute_with_named_argument_0->args[0].name = zend_string_init_interned("arg", sizeof("arg") - 1, 1); } static zend_class_entry *register_class__ZendTestInterface(void) @@ -802,6 +825,34 @@ static zend_class_entry *register_class_ZendTestAttribute(void) return class_entry; } +static zend_class_entry *register_class_ZendTestAttributeWithArguments(void) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "ZendTestAttributeWithArguments", class_ZendTestAttributeWithArguments_methods); + class_entry = zend_register_internal_class_ex(&ce, NULL); + class_entry->ce_flags |= ZEND_ACC_FINAL; + + zval property_arg_default_value; + ZVAL_UNDEF(&property_arg_default_value); + zend_string *property_arg_name = zend_string_init("arg", sizeof("arg") - 1, 1); +#if (PHP_VERSION_ID >= 80100) + zend_declare_typed_property(class_entry, property_arg_name, &property_arg_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ANY)); +#elif (PHP_VERSION_ID >= 80000) + zend_declare_typed_property(class_entry, property_arg_name, &property_arg_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ANY)); +#endif + zend_string_release(property_arg_name); + + zend_string *attribute_name_Attribute_class_ZendTestAttributeWithArguments_0 = zend_string_init_interned("Attribute", sizeof("Attribute") - 1, 1); + zend_attribute *attribute_Attribute_class_ZendTestAttributeWithArguments_0 = zend_add_class_attribute(class_entry, attribute_name_Attribute_class_ZendTestAttributeWithArguments_0, 1); + zend_string_release(attribute_name_Attribute_class_ZendTestAttributeWithArguments_0); + zval attribute_Attribute_class_ZendTestAttributeWithArguments_0_arg0; + ZVAL_LONG(&attribute_Attribute_class_ZendTestAttributeWithArguments_0_arg0, ZEND_ATTRIBUTE_TARGET_ALL); + ZVAL_COPY_VALUE(&attribute_Attribute_class_ZendTestAttributeWithArguments_0->args[0].value, &attribute_Attribute_class_ZendTestAttributeWithArguments_0_arg0); + + return class_entry; +} + static zend_class_entry *register_class_ZendTestRepeatableAttribute(void) { zend_class_entry ce, *class_entry; diff --git a/ext/zend_test/tests/attribute-named-parameter.phpt b/ext/zend_test/tests/attribute-named-parameter.phpt new file mode 100644 index 0000000000000..5c970db26219c --- /dev/null +++ b/ext/zend_test/tests/attribute-named-parameter.phpt @@ -0,0 +1,22 @@ +--TEST-- +Verify that attributes for internal functions correctly support named arguments. +--EXTENSIONS-- +zend_test +--FILE-- +getAttributes()[0]; +var_dump($attribute->getArguments()); +var_dump($attribute->newInstance()); + +?> +--EXPECTF-- +array(1) { + ["arg"]=> + string(3) "foo" +} +object(ZendTestAttributeWithArguments)#3 (1) { + ["arg"]=> + string(3) "foo" +}