Commit 9e9445f7421 for php.net
commit 9e9445f7421c7a55e65305f3887995a54d3da410
Author: Gina Peter Banyard <girgias@php.net>
Date: Fri Jun 26 11:38:41 2026 +0100
ext/reflection: add namespace methods to ReflectionAttribute
Add the ReflectionAttribute::inNamespace(), ReflectionAttribute::getNamespaceName(), and ReflectionAttribute::getShortName() methods.
Closes GH-19556
diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c
index ec060cbbf3e..7fa76c121ca 100644
--- a/ext/reflection/php_reflection.c
+++ b/ext/reflection/php_reflection.c
@@ -7370,6 +7370,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 dd605100f8b..b95f01d2ad2 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 65571f38d43..7da379d7b98 100644
Binary files a/ext/reflection/php_reflection_arginfo.h and b/ext/reflection/php_reflection_arginfo.h differ
diff --git a/ext/reflection/php_reflection_decl.h b/ext/reflection/php_reflection_decl.h
index a87e1635419..555ed84feeb 100644
Binary files a/ext/reflection/php_reflection_decl.h and b/ext/reflection/php_reflection_decl.h differ
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 00000000000..9f465e3c05c
--- /dev/null
+++ b/ext/reflection/tests/attributes/ReflectionAttribute_name_namespace_methods.phpt
@@ -0,0 +1,52 @@
+--TEST--
+ReflectionAttribute name and namespace methods
+--FILE--
+<?php
+
+namespace {
+
+ #[Attribute]
+ class AttrNotNamespace {}
+
+}
+
+namespace A\B {
+
+ #[Attribute]
+ class AttrNamespace {}
+
+ class Foo {
+ #[\Attr]
+ public function fn1() {}
+
+ #[AttrNamespace]
+ public function fn2() {}
+ }
+
+ $rm = new \ReflectionMethod(Foo::class, "fn1");
+ $attribute = $rm->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"