From 3d9c603ecf17fc6a95dff821b613a468597e139d Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Sat, 19 Jun 2021 21:28:18 +0200 Subject: [PATCH 1/2] Bugfix 80097: Have ReflectionAttribute implement Reflector and __toString --- ext/reflection/php_reflection.c | 55 ++++++++++++++++++- ext/reflection/php_reflection.stub.php | 4 +- ext/reflection/php_reflection_arginfo.h | 9 ++- .../tests/ReflectionAttribute_toString.phpt | 26 +++++++++ 4 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 ext/reflection/tests/ReflectionAttribute_toString.phpt diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 5ff8dc6f515ab..9ffe622ba6c7f 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -6397,6 +6397,59 @@ 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; + smart_str str = {0}; + zval tmp; + int i; + + if (zend_parse_parameters_none() == FAILURE) { + RETURN_THROWS(); + } + + GET_REFLECTION_OBJECT_PTR(attr); + + smart_str_append_printf(&str, "Attribute [ "); + smart_str_append_printf(&str, "%s", ZSTR_VAL(attr->data->name)); + smart_str_append_printf(&str, " ]"); + + if (attr->data->argc > 0) { + smart_str_append_printf(&str, " {\n"); + smart_str_append_printf(&str, " - Arguments [%d] {\n", attr->data->argc); + + for (i = 0; i < attr->data->argc; i++) { + if (FAILURE == zend_get_attribute_value(&tmp, attr->data, i, attr->scope)) { + RETURN_THROWS(); + } + + if (attr->data->args[i].name != NULL) { + smart_str_append_printf(&str, " Argument #%d [ %s = ", i, ZSTR_VAL(attr->data->args[i].name)); + } else { + smart_str_append_printf(&str, " Argument #%d [ ", i); + } + + if (format_default_value(&str, &tmp, NULL) == FAILURE) { + return; + } + + smart_str_append_printf(&str, " ]\n"); + + zval_ptr_dtor(&tmp); + } + smart_str_append_printf(&str, " }\n"); + + smart_str_append_printf(&str, "}\n"); + } else { + smart_str_append_printf(&str, "\n"); + } + + RETURN_STR(smart_str_extract(&str)); +} +/* }}} */ + /* {{{ * Returns the name of the attribute */ ZEND_METHOD(ReflectionAttribute, getName) { @@ -7062,7 +7115,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 b7bff087c5785..518aa37b41f94 100644 --- a/ext/reflection/php_reflection.stub.php +++ b/ext/reflection/php_reflection.stub.php @@ -680,7 +680,7 @@ private function __clone(): void {} private function __construct() {} } -final class ReflectionAttribute +final class ReflectionAttribute implements Reflector { public function getName(): string {} public function getTarget(): int {} @@ -688,6 +688,8 @@ public function isRepeated(): bool {} 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 6e65f2cf20b8a..c6b93d1221354 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: b7cb399903fb1965ba6294c4dcf9364539e93b5b */ + * Stub hash: 3a424463071c9252fd0b6551d8b6e794f139f8f7 */ 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) @@ -539,6 +539,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 @@ -794,6 +796,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); @@ -1117,6 +1120,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 @@ -1412,13 +1416,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 0000000000000..7c34567d7fb62 --- /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 ] + } +} From 16f52a9ce25ffe5cb375bc94897494282017dba3 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Tue, 29 Jun 2021 10:48:24 +0200 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Nikita Popov --- ext/reflection/php_reflection.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 9ffe622ba6c7f..c4fa630fed017 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -6412,8 +6412,8 @@ ZEND_METHOD(ReflectionAttribute, __toString) GET_REFLECTION_OBJECT_PTR(attr); - smart_str_append_printf(&str, "Attribute [ "); - smart_str_append_printf(&str, "%s", ZSTR_VAL(attr->data->name)); + smart_str_appends(&str, "Attribute [ "); + smart_str_append(&str, "%s", attr->data->name); smart_str_append_printf(&str, " ]"); if (attr->data->argc > 0) {