From b2bac7aecb4cdb94f5932214d8d7eaff5c1892ba Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Fri, 26 Jun 2026 11:40:10 +0100 Subject: [PATCH 1/2] ext/reflection: move ReflectionAttribute tests into subfolder --- .../{ => attributes}/ReflectionAttribute_constructor_001.phpt | 0 .../ReflectionAttribute_newInstance_deprecated.phpt | 0 .../ReflectionAttribute_newInstance_exception.phpt | 0 .../tests/{ => attributes}/ReflectionAttribute_toString.phpt | 0 ext/reflection/tests/{ => attributes}/gh12908.phpt | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename ext/reflection/tests/{ => attributes}/ReflectionAttribute_constructor_001.phpt (100%) rename ext/reflection/tests/{ => attributes}/ReflectionAttribute_newInstance_deprecated.phpt (100%) rename ext/reflection/tests/{ => attributes}/ReflectionAttribute_newInstance_exception.phpt (100%) rename ext/reflection/tests/{ => attributes}/ReflectionAttribute_toString.phpt (100%) rename ext/reflection/tests/{ => attributes}/gh12908.phpt (100%) diff --git a/ext/reflection/tests/ReflectionAttribute_constructor_001.phpt b/ext/reflection/tests/attributes/ReflectionAttribute_constructor_001.phpt similarity index 100% rename from ext/reflection/tests/ReflectionAttribute_constructor_001.phpt rename to ext/reflection/tests/attributes/ReflectionAttribute_constructor_001.phpt diff --git a/ext/reflection/tests/ReflectionAttribute_newInstance_deprecated.phpt b/ext/reflection/tests/attributes/ReflectionAttribute_newInstance_deprecated.phpt similarity index 100% rename from ext/reflection/tests/ReflectionAttribute_newInstance_deprecated.phpt rename to ext/reflection/tests/attributes/ReflectionAttribute_newInstance_deprecated.phpt diff --git a/ext/reflection/tests/ReflectionAttribute_newInstance_exception.phpt b/ext/reflection/tests/attributes/ReflectionAttribute_newInstance_exception.phpt similarity index 100% rename from ext/reflection/tests/ReflectionAttribute_newInstance_exception.phpt rename to ext/reflection/tests/attributes/ReflectionAttribute_newInstance_exception.phpt diff --git a/ext/reflection/tests/ReflectionAttribute_toString.phpt b/ext/reflection/tests/attributes/ReflectionAttribute_toString.phpt similarity index 100% rename from ext/reflection/tests/ReflectionAttribute_toString.phpt rename to ext/reflection/tests/attributes/ReflectionAttribute_toString.phpt diff --git a/ext/reflection/tests/gh12908.phpt b/ext/reflection/tests/attributes/gh12908.phpt similarity index 100% rename from ext/reflection/tests/gh12908.phpt rename to ext/reflection/tests/attributes/gh12908.phpt From dee39a781ecbcf78874dca134fe0f11165414508 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Fri, 26 Jun 2026 11:38:41 +0100 Subject: [PATCH 2/2] ext/reflection: add namespace methods to ReflectionAttribute Add the ReflectionAttribute::inNamespace(), ReflectionAttribute::getNamespaceName(), and ReflectionAttribute::getShortName() methods. Closes GH-19556 --- ext/reflection/php_reflection.c | 52 +++++++++++++++++++ ext/reflection/php_reflection.stub.php | 3 ++ ext/reflection/php_reflection_arginfo.h | 14 ++++- ext/reflection/php_reflection_decl.h | 8 +-- ...ctionAttribute_name_namespace_methods.phpt | 52 +++++++++++++++++++ 5 files changed, 124 insertions(+), 5 deletions(-) create mode 100644 ext/reflection/tests/attributes/ReflectionAttribute_name_namespace_methods.phpt diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index a9f6b579977e..845a648c523a 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -7493,6 +7493,58 @@ ZEND_METHOD(ReflectionAttribute, getName) } /* }}} */ +/* Returns whether this attribute name comes from a namespace */ +ZEND_METHOD(ReflectionAttribute, inNamespace) +{ + reflection_object *intern; + attribute_reference *attr; + + ZEND_PARSE_PARAMETERS_NONE(); + + GET_REFLECTION_OBJECT_PTR(attr); + + const zend_string *name = attr->data->name; + const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)); + RETURN_BOOL(backslash); +} +/* }}} */ + +/* Returns the name of namespace where this attribute comes from */ +ZEND_METHOD(ReflectionAttribute, getNamespaceName) +{ + reflection_object *intern; + attribute_reference *attr; + + ZEND_PARSE_PARAMETERS_NONE(); + + GET_REFLECTION_OBJECT_PTR(attr); + + const zend_string *name = attr->data->name; + const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)); + if (backslash) { + RETURN_STRINGL(ZSTR_VAL(name), backslash - ZSTR_VAL(name)); + } + RETURN_EMPTY_STRING(); +} + +/* Returns the short name of the attribute (without namespace part) */ +ZEND_METHOD(ReflectionAttribute, getShortName) +{ + reflection_object *intern; + attribute_reference *attr; + + ZEND_PARSE_PARAMETERS_NONE(); + + GET_REFLECTION_OBJECT_PTR(attr); + + zend_string *name = attr->data->name; + const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)); + if (backslash) { + RETURN_STRINGL(backslash + 1, ZSTR_LEN(name) - (backslash - ZSTR_VAL(name) + 1)); + } + RETURN_STR_COPY(name); +} + /* {{{ Returns the target of the attribute */ ZEND_METHOD(ReflectionAttribute, getTarget) { diff --git a/ext/reflection/php_reflection.stub.php b/ext/reflection/php_reflection.stub.php index dd605100f8ba..b95f01d2ad28 100644 --- a/ext/reflection/php_reflection.stub.php +++ b/ext/reflection/php_reflection.stub.php @@ -849,6 +849,9 @@ class ReflectionAttribute implements Reflector public string $name; public function getName(): string {} + public function inNamespace(): bool {} + public function getNamespaceName(): string {} + public function getShortName(): string {} public function getTarget(): int {} public function isRepeated(): bool {} public function getArguments(): array {} diff --git a/ext/reflection/php_reflection_arginfo.h b/ext/reflection/php_reflection_arginfo.h index 65571f38d43c..7da379d7b989 100644 --- a/ext/reflection/php_reflection_arginfo.h +++ b/ext/reflection/php_reflection_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit php_reflection.stub.php instead. - * Stub hash: c80946cc8c8215bb6527e09bb71b3a97a76a6a98 + * Stub hash: c4dcc2653f826c2c437065faec4bf77772ef88b1 * Has decl header: yes */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_Reflection_getModifierNames, 0, 1, IS_ARRAY, 0) @@ -646,6 +646,12 @@ ZEND_END_ARG_INFO() #define arginfo_class_ReflectionAttribute_getName arginfo_class_ReflectionFunction___toString +#define arginfo_class_ReflectionAttribute_inNamespace arginfo_class_ReflectionFunctionAbstract_hasTentativeReturnType + +#define arginfo_class_ReflectionAttribute_getNamespaceName arginfo_class_ReflectionFunction___toString + +#define arginfo_class_ReflectionAttribute_getShortName arginfo_class_ReflectionFunction___toString + #define arginfo_class_ReflectionAttribute_getTarget arginfo_class_ReflectionGenerator_getExecutingLine #define arginfo_class_ReflectionAttribute_isRepeated arginfo_class_ReflectionFunctionAbstract_hasTentativeReturnType @@ -974,6 +980,9 @@ ZEND_METHOD(ReflectionReference, fromArrayElement); ZEND_METHOD(ReflectionReference, getId); ZEND_METHOD(ReflectionReference, __construct); ZEND_METHOD(ReflectionAttribute, getName); +ZEND_METHOD(ReflectionAttribute, inNamespace); +ZEND_METHOD(ReflectionAttribute, getNamespaceName); +ZEND_METHOD(ReflectionAttribute, getShortName); ZEND_METHOD(ReflectionAttribute, getTarget); ZEND_METHOD(ReflectionAttribute, isRepeated); ZEND_METHOD(ReflectionAttribute, getArguments); @@ -1327,6 +1336,9 @@ static const zend_function_entry class_ReflectionReference_methods[] = { static const zend_function_entry class_ReflectionAttribute_methods[] = { ZEND_ME(ReflectionAttribute, getName, arginfo_class_ReflectionAttribute_getName, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionAttribute, inNamespace, arginfo_class_ReflectionAttribute_inNamespace, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionAttribute, getNamespaceName, arginfo_class_ReflectionAttribute_getNamespaceName, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionAttribute, getShortName, arginfo_class_ReflectionAttribute_getShortName, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionAttribute, getTarget, arginfo_class_ReflectionAttribute_getTarget, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionAttribute, isRepeated, arginfo_class_ReflectionAttribute_isRepeated, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionAttribute, getArguments, arginfo_class_ReflectionAttribute_getArguments, ZEND_ACC_PUBLIC) diff --git a/ext/reflection/php_reflection_decl.h b/ext/reflection/php_reflection_decl.h index a87e1635419b..555ed84feebe 100644 --- a/ext/reflection/php_reflection_decl.h +++ b/ext/reflection/php_reflection_decl.h @@ -1,12 +1,12 @@ /* This is a generated file, edit php_reflection.stub.php instead. - * Stub hash: c80946cc8c8215bb6527e09bb71b3a97a76a6a98 */ + * Stub hash: c4dcc2653f826c2c437065faec4bf77772ef88b1 */ -#ifndef ZEND_PHP_REFLECTION_DECL_c80946cc8c8215bb6527e09bb71b3a97a76a6a98_H -#define ZEND_PHP_REFLECTION_DECL_c80946cc8c8215bb6527e09bb71b3a97a76a6a98_H +#ifndef ZEND_PHP_REFLECTION_DECL_c4dcc2653f826c2c437065faec4bf77772ef88b1_H +#define ZEND_PHP_REFLECTION_DECL_c4dcc2653f826c2c437065faec4bf77772ef88b1_H typedef enum zend_enum_PropertyHookType { ZEND_ENUM_PropertyHookType_Get = 1, ZEND_ENUM_PropertyHookType_Set = 2, } zend_enum_PropertyHookType; -#endif /* ZEND_PHP_REFLECTION_DECL_c80946cc8c8215bb6527e09bb71b3a97a76a6a98_H */ +#endif /* ZEND_PHP_REFLECTION_DECL_c4dcc2653f826c2c437065faec4bf77772ef88b1_H */ diff --git a/ext/reflection/tests/attributes/ReflectionAttribute_name_namespace_methods.phpt b/ext/reflection/tests/attributes/ReflectionAttribute_name_namespace_methods.phpt new file mode 100644 index 000000000000..9f465e3c05cd --- /dev/null +++ b/ext/reflection/tests/attributes/ReflectionAttribute_name_namespace_methods.phpt @@ -0,0 +1,52 @@ +--TEST-- +ReflectionAttribute name and namespace methods +--FILE-- +getAttributes()[0]; + + var_dump($attribute->inNamespace()); + var_dump($attribute->getName()); + var_dump($attribute->getNamespaceName()); + var_dump($attribute->getShortName()); + + $rm = new \ReflectionMethod(Foo::class, "fn2"); + $attribute = $rm->getAttributes()[0]; + + var_dump($attribute->inNamespace()); + var_dump($attribute->getName()); + var_dump($attribute->getNamespaceName()); + var_dump($attribute->getShortName()); +} + +?> +--EXPECT-- +bool(false) +string(4) "Attr" +string(0) "" +string(4) "Attr" +bool(true) +string(17) "A\B\AttrNamespace" +string(3) "A\B" +string(13) "AttrNamespace"