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"