From bc39abe8c3c492e29bc5d60ca58442040bbf063b Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Sat, 19 Jun 2021 21:28:18 +0200 Subject: [PATCH] Fix #80097: Have ReflectionAttribute implement Reflector and __toString Implement printing for ReflectionAttribute. Attributes aren't printed as part of reflection output for other structures (classes etc) yet. Closes GH-6117. --- NEWS | 3 +- ext/reflection/php_reflection.c | 53 ++++++++++++++++++- ext/reflection/php_reflection.stub.php | 4 +- ext/reflection/php_reflection_arginfo.h | 9 +++- .../tests/ReflectionAttribute_toString.phpt | 26 +++++++++ 5 files changed, 90 insertions(+), 5 deletions(-) create mode 100644 ext/reflection/tests/ReflectionAttribute_toString.phpt diff --git a/NEWS b/NEWS index f8b7dfee209..2e6195e32a0 100644 --- a/NEWS +++ b/NEWS @@ -2,7 +2,8 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.1.0beta1 - +- Reflection: + . Fixed bug #80097 (ReflectionAttribute is not a Reflector). (beberlei) 08 Jul 2021, PHP 8.1.0alpha3 diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 44e8cbe25bf..7a3bdf51419 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -6452,6 +6452,57 @@ ZEND_METHOD(ReflectionAttribute, __clone) _DO_THROW("Cannot clone object using __clone()"); } +/* {{{ Returns a string representation */ +ZEND_METHOD(ReflectionAttribute, __toString) +{ + reflection_object *intern; + attribute_reference *attr; + + if (zend_parse_parameters_none() == FAILURE) { + RETURN_THROWS(); + } + + GET_REFLECTION_OBJECT_PTR(attr); + + smart_str str = {0}; + smart_str_appends(&str, "Attribute [ "); + smart_str_append(&str, attr->data->name); + smart_str_appends(&str, " ]"); + + if (attr->data->argc > 0) { + smart_str_appends(&str, " {\n"); + smart_str_append_printf(&str, " - Arguments [%d] {\n", attr->data->argc); + + for (uint32_t i = 0; i < attr->data->argc; i++) { + zval tmp; + if (FAILURE == zend_get_attribute_value(&tmp, attr->data, i, attr->scope)) { + RETURN_THROWS(); + } + + smart_str_append_printf(&str, " Argument #%d [ ", i); + if (attr->data->args[i].name != NULL) { + smart_str_append(&str, attr->data->args[i].name); + smart_str_appends(&str, " = "); + } + + if (format_default_value(&str, &tmp, NULL) == FAILURE) { + return; + } + + smart_str_appends(&str, " ]\n"); + zval_ptr_dtor(&tmp); + } + smart_str_appends(&str, " }\n"); + + smart_str_appends(&str, "}\n"); + } else { + smart_str_appendc(&str, '\n'); + } + + RETURN_STR(smart_str_extract(&str)); +} +/* }}} */ + /* {{{ * Returns the name of the attribute */ ZEND_METHOD(ReflectionAttribute, getName) { @@ -7121,7 +7172,7 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */ reflection_reference_ptr = register_class_ReflectionReference(); reflection_init_class_handlers(reflection_reference_ptr); - reflection_attribute_ptr = register_class_ReflectionAttribute(); + reflection_attribute_ptr = register_class_ReflectionAttribute(reflector_ptr); reflection_init_class_handlers(reflection_attribute_ptr); reflection_enum_ptr = register_class_ReflectionEnum(reflection_class_ptr); diff --git a/ext/reflection/php_reflection.stub.php b/ext/reflection/php_reflection.stub.php index c70a49c7756..54ddad3bc50 100644 --- a/ext/reflection/php_reflection.stub.php +++ b/ext/reflection/php_reflection.stub.php @@ -687,7 +687,7 @@ final class ReflectionReference private function __construct() {} } -final class ReflectionAttribute +final class ReflectionAttribute implements Reflector { public function getName(): string {} public function getTarget(): int {} @@ -695,6 +695,8 @@ final class ReflectionAttribute public function getArguments(): array {} public function newInstance(): object {} + public function __toString(): string {} + private function __clone(): void {} private function __construct() {} diff --git a/ext/reflection/php_reflection_arginfo.h b/ext/reflection/php_reflection_arginfo.h index 7330fe680f3..5645ba07049 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 the .stub.php file instead. - * Stub hash: 2564122a201ca462ee35ead1562c94da3ea3c8a3 */ + * Stub hash: b70561858fb66134ce9596921215881fd9b946c0 */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_Reflection_getModifierNames, 0, 1, IS_ARRAY, 0) ZEND_ARG_TYPE_INFO(0, modifiers, IS_LONG, 0) @@ -543,6 +543,8 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionAttribute_newInstance, 0, 0, IS_OBJECT, 0) ZEND_END_ARG_INFO() +#define arginfo_class_ReflectionAttribute___toString arginfo_class_ReflectionFunction___toString + #define arginfo_class_ReflectionAttribute___clone arginfo_class_ReflectionFunctionAbstract___clone #define arginfo_class_ReflectionAttribute___construct arginfo_class_ReflectionReference___construct @@ -800,6 +802,7 @@ ZEND_METHOD(ReflectionAttribute, getTarget); ZEND_METHOD(ReflectionAttribute, isRepeated); ZEND_METHOD(ReflectionAttribute, getArguments); ZEND_METHOD(ReflectionAttribute, newInstance); +ZEND_METHOD(ReflectionAttribute, __toString); ZEND_METHOD(ReflectionAttribute, __clone); ZEND_METHOD(ReflectionAttribute, __construct); ZEND_METHOD(ReflectionEnum, __construct); @@ -1130,6 +1133,7 @@ static const zend_function_entry class_ReflectionAttribute_methods[] = { ZEND_ME(ReflectionAttribute, isRepeated, arginfo_class_ReflectionAttribute_isRepeated, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionAttribute, getArguments, arginfo_class_ReflectionAttribute_getArguments, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionAttribute, newInstance, arginfo_class_ReflectionAttribute_newInstance, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionAttribute, __toString, arginfo_class_ReflectionAttribute___toString, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionAttribute, __clone, arginfo_class_ReflectionAttribute___clone, ZEND_ACC_PRIVATE) ZEND_ME(ReflectionAttribute, __construct, arginfo_class_ReflectionAttribute___construct, ZEND_ACC_PRIVATE) ZEND_FE_END @@ -1435,13 +1439,14 @@ static zend_class_entry *register_class_ReflectionReference(void) return class_entry; } -static zend_class_entry *register_class_ReflectionAttribute(void) +static zend_class_entry *register_class_ReflectionAttribute(zend_class_entry *class_entry_Reflector) { zend_class_entry ce, *class_entry; INIT_CLASS_ENTRY(ce, "ReflectionAttribute", class_ReflectionAttribute_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_FINAL; + zend_class_implements(class_entry, 1, class_entry_Reflector); return class_entry; } diff --git a/ext/reflection/tests/ReflectionAttribute_toString.phpt b/ext/reflection/tests/ReflectionAttribute_toString.phpt new file mode 100644 index 00000000000..7c34567d7fb --- /dev/null +++ b/ext/reflection/tests/ReflectionAttribute_toString.phpt @@ -0,0 +1,26 @@ +--TEST-- +ReflectionAttribute::__toString +--FILE-- +getAttributes()[0]; +echo $refl->getAttributes()[1]; +echo $refl->getAttributes()[2]; +--EXPECTF-- +Attribute [ Foo ] +Attribute [ Bar ] { + - Arguments [2] { + Argument #0 [ a = 'foo' ] + Argument #1 [ b = 1234 ] + } +} +Attribute [ Baz ] { + - Arguments [2] { + Argument #0 [ 'foo' ] + Argument #1 [ 1234 ] + } +}