diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 54f1f46ce4964..ebef8948f35a5 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -74,6 +74,7 @@ static zend_always_inline zval *reflection_prop_class(zval *object) { /* Class entry pointers */ PHPAPI zend_class_entry *reflector_ptr; +PHPAPI zend_class_entry *reflector_with_attributes_ptr; PHPAPI zend_class_entry *reflection_exception_ptr; PHPAPI zend_class_entry *reflection_ptr; PHPAPI zend_class_entry *reflection_function_abstract_ptr; @@ -1165,7 +1166,7 @@ static void reflection_attribute_factory(zval *object, HashTable *attributes, ze /* }}} */ static int read_attributes(zval *ret, HashTable *attributes, zend_class_entry *scope, - uint32_t offset, uint32_t target, zend_string *name, zend_class_entry *base, zend_string *filename) /* {{{ */ + uint32_t offset, uint32_t target, zend_string *name, zend_class_entry *base, zend_string *filename, bool first) /* {{{ */ { ZEND_ASSERT(attributes != NULL); @@ -1178,7 +1179,12 @@ static int read_attributes(zval *ret, HashTable *attributes, zend_class_entry *s ZEND_HASH_PACKED_FOREACH_PTR(attributes, attr) { if (attr->offset == offset && zend_string_equals(attr->lcname, filter)) { - reflection_attribute_factory(&tmp, attributes, attr, scope, target, filename); + reflection_attribute_factory(first ? ret : &tmp, attributes, attr, scope, target, filename); + + if (first) { + break; + } + add_next_index_zval(ret, &tmp); } } ZEND_HASH_FOREACH_END(); @@ -1210,7 +1216,12 @@ static int read_attributes(zval *ret, HashTable *attributes, zend_class_entry *s } } - reflection_attribute_factory(&tmp, attributes, attr, scope, target, filename); + reflection_attribute_factory(first ? ret : &tmp, attributes, attr, scope, target, filename); + + if (first) { + break; + } + add_next_index_zval(ret, &tmp); } ZEND_HASH_FOREACH_END(); @@ -1219,7 +1230,7 @@ static int read_attributes(zval *ret, HashTable *attributes, zend_class_entry *s /* }}} */ static void reflect_attributes(INTERNAL_FUNCTION_PARAMETERS, HashTable *attributes, - uint32_t offset, zend_class_entry *scope, uint32_t target, zend_string *filename) /* {{{ */ + uint32_t offset, zend_class_entry *scope, uint32_t target, zend_string *filename, bool first) /* {{{ */ { zend_string *name = NULL; zend_long flags = 0; @@ -1247,14 +1258,20 @@ static void reflect_attributes(INTERNAL_FUNCTION_PARAMETERS, HashTable *attribut } if (!attributes) { - RETURN_EMPTY_ARRAY(); + if (first) { + RETURN_NULL(); + } else { + RETURN_EMPTY_ARRAY(); + } } - array_init(return_value); + if (! first) { + array_init(return_value); + } - if (FAILURE == read_attributes(return_value, attributes, scope, offset, target, name, base, filename)) { - RETURN_THROWS(); - } + if (FAILURE == read_attributes(return_value, attributes, scope, offset, target, name, base, filename, first)) { + RETURN_THROWS(); + } } /* }}} */ @@ -1985,10 +2002,37 @@ ZEND_METHOD(ReflectionFunctionAbstract, getAttributes) reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU, fptr->common.attributes, 0, fptr->common.scope, target, - fptr->type == ZEND_USER_FUNCTION ? fptr->op_array.filename : NULL); + fptr->type == ZEND_USER_FUNCTION ? fptr->op_array.filename : NULL, false); } /* }}} */ + +/* {{{ Returns the first attribute of this function */ +ZEND_METHOD(ReflectionFunctionAbstract, getFirstAttribute) +{ + reflection_object *intern; + zend_function *fptr; + uint32_t target; + zend_string *name = NULL; + zend_long flags = 0; + + GET_REFLECTION_OBJECT_PTR(fptr); + + if (fptr->common.scope && (fptr->common.fn_flags & (ZEND_ACC_CLOSURE|ZEND_ACC_FAKE_CLOSURE)) != ZEND_ACC_CLOSURE) { + target = ZEND_ATTRIBUTE_TARGET_METHOD; + } else { + target = ZEND_ATTRIBUTE_TARGET_FUNCTION; + } + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!l", &name, &flags) == FAILURE) { + RETURN_THROWS(); + } + + reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU, + fptr->common.attributes, 0, fptr->common.scope, target, + fptr->type == ZEND_USER_FUNCTION ? fptr->op_array.filename : NULL, true); +} +/* }}} */ /* {{{ Returns an associative array containing this function's static variables and their values */ ZEND_METHOD(ReflectionFunctionAbstract, getStaticVariables) { @@ -2866,8 +2910,26 @@ ZEND_METHOD(ReflectionParameter, getAttributes) reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU, attributes, param->offset + 1, scope, ZEND_ATTRIBUTE_TARGET_PARAMETER, - param->fptr->type == ZEND_USER_FUNCTION ? param->fptr->op_array.filename : NULL); + param->fptr->type == ZEND_USER_FUNCTION ? param->fptr->op_array.filename : NULL, false); } +/* }}} */ + +/* {{{ Get the first parameter attribute. */ +ZEND_METHOD(ReflectionParameter, getFirstAttribute) +{ + reflection_object *intern; + parameter_reference *param; + + GET_REFLECTION_OBJECT_PTR(param); + + HashTable *attributes = param->fptr->common.attributes; + zend_class_entry *scope = param->fptr->common.scope; + + reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU, + attributes, param->offset + 1, scope, ZEND_ATTRIBUTE_TARGET_PARAMETER, + param->fptr->type == ZEND_USER_FUNCTION ? param->fptr->op_array.filename : NULL, true); +} +/* }}} */ /* {{{ Returns whether this parameter is an optional parameter */ ZEND_METHOD(ReflectionParameter, getPosition) @@ -4053,7 +4115,21 @@ ZEND_METHOD(ReflectionClassConstant, getAttributes) reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU, ref->attributes, 0, ref->ce, ZEND_ATTRIBUTE_TARGET_CLASS_CONST, - ref->ce->type == ZEND_USER_CLASS ? ref->ce->info.user.filename : NULL); + ref->ce->type == ZEND_USER_CLASS ? ref->ce->info.user.filename : NULL, false); +} +/* }}} */ + +/* {{{ Returns the first attribute of this constant */ +ZEND_METHOD(ReflectionClassConstant, getFirstAttribute) +{ + reflection_object *intern; + zend_class_constant *ref; + + GET_REFLECTION_OBJECT_PTR(ref); + + reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU, + ref->attributes, 0, ref->ce, ZEND_ATTRIBUTE_TARGET_CLASS_CONST, + ref->ce->type == ZEND_USER_CLASS ? ref->ce->info.user.filename : NULL, true); } /* }}} */ @@ -4475,7 +4551,21 @@ ZEND_METHOD(ReflectionClass, getAttributes) reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU, ce->attributes, 0, ce, ZEND_ATTRIBUTE_TARGET_CLASS, - ce->type == ZEND_USER_CLASS ? ce->info.user.filename : NULL); + ce->type == ZEND_USER_CLASS ? ce->info.user.filename : NULL, false); +} +/* }}} */ + +/* {{{ Returns the first attribute for this class */ +ZEND_METHOD(ReflectionClass, getFirstAttribute) +{ + reflection_object *intern; + zend_class_entry *ce; + + GET_REFLECTION_OBJECT_PTR(ce); + + reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU, + ce->attributes, 0, ce, ZEND_ATTRIBUTE_TARGET_CLASS, + ce->type == ZEND_USER_CLASS ? ce->info.user.filename : NULL, true); } /* }}} */ @@ -5912,7 +6002,25 @@ ZEND_METHOD(ReflectionProperty, getAttributes) reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU, ref->prop->attributes, 0, ref->prop->ce, ZEND_ATTRIBUTE_TARGET_PROPERTY, - ref->prop->ce->type == ZEND_USER_CLASS ? ref->prop->ce->info.user.filename : NULL); + ref->prop->ce->type == ZEND_USER_CLASS ? ref->prop->ce->info.user.filename : NULL, false); +} +/* }}} */ + +/* {{{ Returns the first attribute of this property */ +ZEND_METHOD(ReflectionProperty, getFirstAttribute) +{ + reflection_object *intern; + property_reference *ref; + + GET_REFLECTION_OBJECT_PTR(ref); + + if (ref->prop == NULL) { + RETURN_EMPTY_ARRAY(); + } + + reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU, + ref->prop->attributes, 0, ref->prop->ce, ZEND_ATTRIBUTE_TARGET_PROPERTY, + ref->prop->ce->type == ZEND_USER_CLASS ? ref->prop->ce->info.user.filename : NULL, true); } /* }}} */ @@ -7402,7 +7510,9 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */ reflector_ptr = register_class_Reflector(zend_ce_stringable); - reflection_function_abstract_ptr = register_class_ReflectionFunctionAbstract(reflector_ptr); + reflector_with_attributes_ptr = register_class_ReflectorWithAttributes(); + + reflection_function_abstract_ptr = register_class_ReflectionFunctionAbstract(reflector_ptr, reflector_with_attributes_ptr); reflection_function_abstract_ptr->default_object_handlers = &reflection_object_handlers; reflection_function_abstract_ptr->create_object = reflection_objects_new; @@ -7414,7 +7524,7 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */ reflection_generator_ptr->create_object = reflection_objects_new; reflection_generator_ptr->default_object_handlers = &reflection_object_handlers; - reflection_parameter_ptr = register_class_ReflectionParameter(reflector_ptr); + reflection_parameter_ptr = register_class_ReflectionParameter(reflector_ptr, reflector_with_attributes_ptr); reflection_parameter_ptr->create_object = reflection_objects_new; reflection_parameter_ptr->default_object_handlers = &reflection_object_handlers; @@ -7438,7 +7548,7 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */ reflection_method_ptr->create_object = reflection_objects_new; reflection_method_ptr->default_object_handlers = &reflection_object_handlers; - reflection_class_ptr = register_class_ReflectionClass(reflector_ptr); + reflection_class_ptr = register_class_ReflectionClass(reflector_ptr, reflector_with_attributes_ptr); reflection_class_ptr->create_object = reflection_objects_new; reflection_class_ptr->default_object_handlers = &reflection_object_handlers; @@ -7446,7 +7556,7 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */ reflection_object_ptr->create_object = reflection_objects_new; reflection_object_ptr->default_object_handlers = &reflection_object_handlers; - reflection_property_ptr = register_class_ReflectionProperty(reflector_ptr); + reflection_property_ptr = register_class_ReflectionProperty(reflector_ptr, reflector_with_attributes_ptr); reflection_property_ptr->create_object = reflection_objects_new; reflection_property_ptr->default_object_handlers = &reflection_object_handlers; diff --git a/ext/reflection/php_reflection.h b/ext/reflection/php_reflection.h index 6420b04520aa6..02dd154eefda8 100644 --- a/ext/reflection/php_reflection.h +++ b/ext/reflection/php_reflection.h @@ -28,6 +28,7 @@ BEGIN_EXTERN_C() /* Class entry pointers */ extern PHPAPI zend_class_entry *reflector_ptr; +extern PHPAPI zend_class_entry *reflector_with_attributes_ptr; extern PHPAPI zend_class_entry *reflection_exception_ptr; extern PHPAPI zend_class_entry *reflection_ptr; extern PHPAPI zend_class_entry *reflection_function_abstract_ptr; diff --git a/ext/reflection/php_reflection.stub.php b/ext/reflection/php_reflection.stub.php index d3eee1ee3cf5c..7a9232fde8503 100644 --- a/ext/reflection/php_reflection.stub.php +++ b/ext/reflection/php_reflection.stub.php @@ -16,8 +16,15 @@ interface Reflector extends Stringable { } +interface ReflectorWithAttributes +{ + public function getAttributes(?string $name = null, int $flags = 0): array; + + public function getFirstAttribute(?string $name = null, int $flags = 0): ?ReflectionAttribute; +} + /** @not-serializable */ -abstract class ReflectionFunctionAbstract implements Reflector +abstract class ReflectionFunctionAbstract implements Reflector, ReflectorWithAttributes { public string $name; @@ -111,7 +118,9 @@ public function hasTentativeReturnType(): bool {} public function getTentativeReturnType(): ?ReflectionType {} - public function getAttributes(?string $name = null, int $flags = 0): array {} + public function getAttributes(?string $name = null, int $flags = 0): array; + + public function getFirstAttribute(?string $name = null, int $flags = 0): ?ReflectionAttribute; } class ReflectionFunction extends ReflectionFunctionAbstract @@ -234,7 +243,7 @@ public function setAccessible(bool $accessible): void {} } /** @not-serializable */ -class ReflectionClass implements Reflector +class ReflectionClass implements Reflector, ReflectorWithAttributes { /** * @cvalue ZEND_ACC_IMPLICIT_ABSTRACT_CLASS @@ -414,6 +423,8 @@ public function getNamespaceName(): string {} public function getShortName(): string {} public function getAttributes(?string $name = null, int $flags = 0): array {} + + public function getFirstAttribute(?string $name = null, int $flags = 0): ?ReflectionAttribute; } class ReflectionObject extends ReflectionClass @@ -422,7 +433,7 @@ public function __construct(object $object) {} } /** @not-serializable */ -class ReflectionProperty implements Reflector +class ReflectionProperty implements Reflector, ReflectorWithAttributes { /** @cvalue ZEND_ACC_STATIC */ public const int IS_STATIC = UNKNOWN; @@ -500,6 +511,8 @@ public function hasDefaultValue(): bool {} public function getDefaultValue(): mixed {} public function getAttributes(?string $name = null, int $flags = 0): array {} + + public function getFirstAttribute(?string $name = null, int $flags = 0): ?ReflectionAttribute; } /** @not-serializable */ @@ -550,8 +563,6 @@ public function getDeclaringClass(): ReflectionClass {} /** @tentative-return-type */ public function getDocComment(): string|false {} - public function getAttributes(?string $name = null, int $flags = 0): array {} - public function isEnumCase(): bool {} public function isDeprecated(): bool {} @@ -559,10 +570,14 @@ public function isDeprecated(): bool {} public function hasType(): bool {} public function getType(): ?ReflectionType {} + + public function getAttributes(?string $name = null, int $flags = 0): array {} + + public function getFirstAttribute(?string $name = null, int $flags = 0): ?ReflectionAttribute; } /** @not-serializable */ -class ReflectionParameter implements Reflector +class ReflectionParameter implements Reflector, ReflectorWithAttributes { public string $name; @@ -640,6 +655,8 @@ public function isVariadic(): bool {} public function isPromoted(): bool {} public function getAttributes(?string $name = null, int $flags = 0): array {} + + public function getFirstAttribute(?string $name = null, int $flags = 0): ?ReflectionAttribute; } /** @not-serializable */ diff --git a/ext/reflection/php_reflection_arginfo.h b/ext/reflection/php_reflection_arginfo.h index a1cfc2f69a9c0..a8826f8bfa39f 100644 --- a/ext/reflection/php_reflection_arginfo.h +++ b/ext/reflection/php_reflection_arginfo.h @@ -1,10 +1,20 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: f3fd5084866ba31bfa4e7e2bf78d95107cfe4b61 */ + * Stub hash: 8248b0f0f2568c18537acfad05817be847c4fac4 */ 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) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectorWithAttributes_getAttributes, 0, 0, IS_ARRAY, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, name, IS_STRING, 1, "null") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "0") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_ReflectorWithAttributes_getFirstAttribute, 0, 0, ReflectionAttribute, 1) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, name, IS_STRING, 1, "null") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "0") +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionFunctionAbstract___clone, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO() @@ -81,10 +91,9 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_ReflectionFunctionAbstract_getTentativeReturnType, 0, 0, ReflectionType, 1) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionFunctionAbstract_getAttributes, 0, 0, IS_ARRAY, 0) - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, name, IS_STRING, 1, "null") - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "0") -ZEND_END_ARG_INFO() +#define arginfo_class_ReflectionFunctionAbstract_getAttributes arginfo_class_ReflectorWithAttributes_getAttributes + +#define arginfo_class_ReflectionFunctionAbstract_getFirstAttribute arginfo_class_ReflectorWithAttributes_getFirstAttribute ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ReflectionFunction___construct, 0, 0, 1) ZEND_ARG_OBJ_TYPE_MASK(0, function, Closure, MAY_BE_STRING, NULL) @@ -324,7 +333,9 @@ ZEND_END_ARG_INFO() #define arginfo_class_ReflectionClass_getShortName arginfo_class_ReflectionFunctionAbstract_getName -#define arginfo_class_ReflectionClass_getAttributes arginfo_class_ReflectionFunctionAbstract_getAttributes +#define arginfo_class_ReflectionClass_getAttributes arginfo_class_ReflectorWithAttributes_getAttributes + +#define arginfo_class_ReflectionClass_getFirstAttribute arginfo_class_ReflectorWithAttributes_getFirstAttribute ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ReflectionObject___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, object, IS_OBJECT, 0) @@ -385,7 +396,9 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionProperty_getDefaultValue, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() -#define arginfo_class_ReflectionProperty_getAttributes arginfo_class_ReflectionFunctionAbstract_getAttributes +#define arginfo_class_ReflectionProperty_getAttributes arginfo_class_ReflectorWithAttributes_getAttributes + +#define arginfo_class_ReflectionProperty_getFirstAttribute arginfo_class_ReflectorWithAttributes_getFirstAttribute #define arginfo_class_ReflectionClassConstant___clone arginfo_class_ReflectionFunctionAbstract___clone @@ -414,8 +427,6 @@ ZEND_END_ARG_INFO() #define arginfo_class_ReflectionClassConstant_getDocComment arginfo_class_ReflectionFunctionAbstract_getDocComment -#define arginfo_class_ReflectionClassConstant_getAttributes arginfo_class_ReflectionFunctionAbstract_getAttributes - #define arginfo_class_ReflectionClassConstant_isEnumCase arginfo_class_ReflectionFunctionAbstract_hasTentativeReturnType #define arginfo_class_ReflectionClassConstant_isDeprecated arginfo_class_ReflectionFunctionAbstract_hasTentativeReturnType @@ -424,6 +435,10 @@ ZEND_END_ARG_INFO() #define arginfo_class_ReflectionClassConstant_getType arginfo_class_ReflectionFunctionAbstract_getTentativeReturnType +#define arginfo_class_ReflectionClassConstant_getAttributes arginfo_class_ReflectorWithAttributes_getAttributes + +#define arginfo_class_ReflectionClassConstant_getFirstAttribute arginfo_class_ReflectorWithAttributes_getFirstAttribute + #define arginfo_class_ReflectionParameter___clone arginfo_class_ReflectionFunctionAbstract___clone ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ReflectionParameter___construct, 0, 0, 2) @@ -472,7 +487,9 @@ ZEND_END_ARG_INFO() #define arginfo_class_ReflectionParameter_isPromoted arginfo_class_ReflectionFunctionAbstract_hasTentativeReturnType -#define arginfo_class_ReflectionParameter_getAttributes arginfo_class_ReflectionFunctionAbstract_getAttributes +#define arginfo_class_ReflectionParameter_getAttributes arginfo_class_ReflectorWithAttributes_getAttributes + +#define arginfo_class_ReflectionParameter_getFirstAttribute arginfo_class_ReflectorWithAttributes_getFirstAttribute #define arginfo_class_ReflectionType___clone arginfo_class_ReflectionFunctionAbstract___clone @@ -663,6 +680,7 @@ ZEND_METHOD(ReflectionFunctionAbstract, getReturnType); ZEND_METHOD(ReflectionFunctionAbstract, hasTentativeReturnType); ZEND_METHOD(ReflectionFunctionAbstract, getTentativeReturnType); ZEND_METHOD(ReflectionFunctionAbstract, getAttributes); +ZEND_METHOD(ReflectionFunctionAbstract, getFirstAttribute); ZEND_METHOD(ReflectionFunction, __construct); ZEND_METHOD(ReflectionFunction, __toString); ZEND_METHOD(ReflectionFunction, isAnonymous); @@ -749,6 +767,7 @@ ZEND_METHOD(ReflectionClass, inNamespace); ZEND_METHOD(ReflectionClass, getNamespaceName); ZEND_METHOD(ReflectionClass, getShortName); ZEND_METHOD(ReflectionClass, getAttributes); +ZEND_METHOD(ReflectionClass, getFirstAttribute); ZEND_METHOD(ReflectionObject, __construct); ZEND_METHOD(ReflectionProperty, __construct); ZEND_METHOD(ReflectionProperty, __toString); @@ -772,6 +791,7 @@ ZEND_METHOD(ReflectionProperty, hasType); ZEND_METHOD(ReflectionProperty, hasDefaultValue); ZEND_METHOD(ReflectionProperty, getDefaultValue); ZEND_METHOD(ReflectionProperty, getAttributes); +ZEND_METHOD(ReflectionProperty, getFirstAttribute); ZEND_METHOD(ReflectionClassConstant, __construct); ZEND_METHOD(ReflectionClassConstant, __toString); ZEND_METHOD(ReflectionClassConstant, getName); @@ -783,11 +803,12 @@ ZEND_METHOD(ReflectionClassConstant, isFinal); ZEND_METHOD(ReflectionClassConstant, getModifiers); ZEND_METHOD(ReflectionClassConstant, getDeclaringClass); ZEND_METHOD(ReflectionClassConstant, getDocComment); -ZEND_METHOD(ReflectionClassConstant, getAttributes); ZEND_METHOD(ReflectionClassConstant, isEnumCase); ZEND_METHOD(ReflectionClassConstant, isDeprecated); ZEND_METHOD(ReflectionClassConstant, hasType); ZEND_METHOD(ReflectionClassConstant, getType); +ZEND_METHOD(ReflectionClassConstant, getAttributes); +ZEND_METHOD(ReflectionClassConstant, getFirstAttribute); ZEND_METHOD(ReflectionParameter, __construct); ZEND_METHOD(ReflectionParameter, __toString); ZEND_METHOD(ReflectionParameter, getName); @@ -810,6 +831,7 @@ ZEND_METHOD(ReflectionParameter, getDefaultValueConstantName); ZEND_METHOD(ReflectionParameter, isVariadic); ZEND_METHOD(ReflectionParameter, isPromoted); ZEND_METHOD(ReflectionParameter, getAttributes); +ZEND_METHOD(ReflectionParameter, getFirstAttribute); ZEND_METHOD(ReflectionType, allowsNull); ZEND_METHOD(ReflectionType, __toString); ZEND_METHOD(ReflectionNamedType, getName); @@ -884,6 +906,12 @@ static const zend_function_entry class_Reflector_methods[] = { ZEND_FE_END }; +static const zend_function_entry class_ReflectorWithAttributes_methods[] = { + ZEND_RAW_FENTRY("getAttributes", NULL, arginfo_class_ReflectorWithAttributes_getAttributes, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT, NULL, NULL) + ZEND_RAW_FENTRY("getFirstAttribute", NULL, arginfo_class_ReflectorWithAttributes_getFirstAttribute, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT, NULL, NULL) + ZEND_FE_END +}; + static const zend_function_entry class_ReflectionFunctionAbstract_methods[] = { ZEND_RAW_FENTRY("__clone", zim_ReflectionClass___clone, arginfo_class_ReflectionFunctionAbstract___clone, ZEND_ACC_PRIVATE, NULL, NULL) ZEND_ME(ReflectionFunctionAbstract, inNamespace, arginfo_class_ReflectionFunctionAbstract_inNamespace, ZEND_ACC_PUBLIC) @@ -917,6 +945,7 @@ static const zend_function_entry class_ReflectionFunctionAbstract_methods[] = { ZEND_ME(ReflectionFunctionAbstract, hasTentativeReturnType, arginfo_class_ReflectionFunctionAbstract_hasTentativeReturnType, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionFunctionAbstract, getTentativeReturnType, arginfo_class_ReflectionFunctionAbstract_getTentativeReturnType, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionFunctionAbstract, getAttributes, arginfo_class_ReflectionFunctionAbstract_getAttributes, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionFunctionAbstract, getFirstAttribute, arginfo_class_ReflectionFunctionAbstract_getFirstAttribute, ZEND_ACC_PUBLIC) ZEND_FE_END }; @@ -1021,6 +1050,7 @@ static const zend_function_entry class_ReflectionClass_methods[] = { ZEND_ME(ReflectionClass, getNamespaceName, arginfo_class_ReflectionClass_getNamespaceName, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionClass, getShortName, arginfo_class_ReflectionClass_getShortName, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionClass, getAttributes, arginfo_class_ReflectionClass_getAttributes, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionClass, getFirstAttribute, arginfo_class_ReflectionClass_getFirstAttribute, ZEND_ACC_PUBLIC) ZEND_FE_END }; @@ -1053,6 +1083,7 @@ static const zend_function_entry class_ReflectionProperty_methods[] = { ZEND_ME(ReflectionProperty, hasDefaultValue, arginfo_class_ReflectionProperty_hasDefaultValue, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionProperty, getDefaultValue, arginfo_class_ReflectionProperty_getDefaultValue, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionProperty, getAttributes, arginfo_class_ReflectionProperty_getAttributes, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionProperty, getFirstAttribute, arginfo_class_ReflectionProperty_getFirstAttribute, ZEND_ACC_PUBLIC) ZEND_FE_END }; @@ -1069,11 +1100,12 @@ static const zend_function_entry class_ReflectionClassConstant_methods[] = { ZEND_ME(ReflectionClassConstant, getModifiers, arginfo_class_ReflectionClassConstant_getModifiers, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionClassConstant, getDeclaringClass, arginfo_class_ReflectionClassConstant_getDeclaringClass, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionClassConstant, getDocComment, arginfo_class_ReflectionClassConstant_getDocComment, ZEND_ACC_PUBLIC) - ZEND_ME(ReflectionClassConstant, getAttributes, arginfo_class_ReflectionClassConstant_getAttributes, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionClassConstant, isEnumCase, arginfo_class_ReflectionClassConstant_isEnumCase, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionClassConstant, isDeprecated, arginfo_class_ReflectionClassConstant_isDeprecated, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionClassConstant, hasType, arginfo_class_ReflectionClassConstant_hasType, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionClassConstant, getType, arginfo_class_ReflectionClassConstant_getType, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionClassConstant, getAttributes, arginfo_class_ReflectionClassConstant_getAttributes, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionClassConstant, getFirstAttribute, arginfo_class_ReflectionClassConstant_getFirstAttribute, ZEND_ACC_PUBLIC) ZEND_FE_END }; @@ -1101,6 +1133,7 @@ static const zend_function_entry class_ReflectionParameter_methods[] = { ZEND_ME(ReflectionParameter, isVariadic, arginfo_class_ReflectionParameter_isVariadic, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionParameter, isPromoted, arginfo_class_ReflectionParameter_isPromoted, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionParameter, getAttributes, arginfo_class_ReflectionParameter_getAttributes, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionParameter, getFirstAttribute, arginfo_class_ReflectionParameter_getFirstAttribute, ZEND_ACC_PUBLIC) ZEND_FE_END }; @@ -1252,14 +1285,24 @@ static zend_class_entry *register_class_Reflector(zend_class_entry *class_entry_ return class_entry; } -static zend_class_entry *register_class_ReflectionFunctionAbstract(zend_class_entry *class_entry_Reflector) +static zend_class_entry *register_class_ReflectorWithAttributes(void) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "ReflectorWithAttributes", class_ReflectorWithAttributes_methods); + class_entry = zend_register_internal_interface(&ce); + + return class_entry; +} + +static zend_class_entry *register_class_ReflectionFunctionAbstract(zend_class_entry *class_entry_Reflector, zend_class_entry *class_entry_ReflectorWithAttributes) { zend_class_entry ce, *class_entry; INIT_CLASS_ENTRY(ce, "ReflectionFunctionAbstract", class_ReflectionFunctionAbstract_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_ABSTRACT|ZEND_ACC_NOT_SERIALIZABLE; - zend_class_implements(class_entry, 1, class_entry_Reflector); + zend_class_implements(class_entry, 2, class_entry_Reflector, class_entry_ReflectorWithAttributes); zval property_name_default_value; ZVAL_UNDEF(&property_name_default_value); @@ -1349,14 +1392,14 @@ static zend_class_entry *register_class_ReflectionMethod(zend_class_entry *class return class_entry; } -static zend_class_entry *register_class_ReflectionClass(zend_class_entry *class_entry_Reflector) +static zend_class_entry *register_class_ReflectionClass(zend_class_entry *class_entry_Reflector, zend_class_entry *class_entry_ReflectorWithAttributes) { zend_class_entry ce, *class_entry; INIT_CLASS_ENTRY(ce, "ReflectionClass", class_ReflectionClass_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_NOT_SERIALIZABLE; - zend_class_implements(class_entry, 1, class_entry_Reflector); + zend_class_implements(class_entry, 2, class_entry_Reflector, class_entry_ReflectorWithAttributes); zval const_IS_IMPLICIT_ABSTRACT_value; ZVAL_LONG(&const_IS_IMPLICIT_ABSTRACT_value, ZEND_ACC_IMPLICIT_ABSTRACT_CLASS); @@ -1401,14 +1444,14 @@ static zend_class_entry *register_class_ReflectionObject(zend_class_entry *class return class_entry; } -static zend_class_entry *register_class_ReflectionProperty(zend_class_entry *class_entry_Reflector) +static zend_class_entry *register_class_ReflectionProperty(zend_class_entry *class_entry_Reflector, zend_class_entry *class_entry_ReflectorWithAttributes) { zend_class_entry ce, *class_entry; INIT_CLASS_ENTRY(ce, "ReflectionProperty", class_ReflectionProperty_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_NOT_SERIALIZABLE; - zend_class_implements(class_entry, 1, class_entry_Reflector); + zend_class_implements(class_entry, 2, class_entry_Reflector, class_entry_ReflectorWithAttributes); zval const_IS_STATIC_value; ZVAL_LONG(&const_IS_STATIC_value, ZEND_ACC_STATIC); @@ -1503,14 +1546,14 @@ static zend_class_entry *register_class_ReflectionClassConstant(zend_class_entry return class_entry; } -static zend_class_entry *register_class_ReflectionParameter(zend_class_entry *class_entry_Reflector) +static zend_class_entry *register_class_ReflectionParameter(zend_class_entry *class_entry_Reflector, zend_class_entry *class_entry_ReflectorWithAttributes) { zend_class_entry ce, *class_entry; INIT_CLASS_ENTRY(ce, "ReflectionParameter", class_ReflectionParameter_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_NOT_SERIALIZABLE; - zend_class_implements(class_entry, 1, class_entry_Reflector); + zend_class_implements(class_entry, 2, class_entry_Reflector, class_entry_ReflectorWithAttributes); zval property_name_default_value; ZVAL_UNDEF(&property_name_default_value); diff --git a/ext/reflection/tests/ReflectionClass_toString_001.phpt b/ext/reflection/tests/ReflectionClass_toString_001.phpt index 15059211ef01d..8c4ce51c10656 100644 --- a/ext/reflection/tests/ReflectionClass_toString_001.phpt +++ b/ext/reflection/tests/ReflectionClass_toString_001.phpt @@ -9,7 +9,7 @@ $rc = new ReflectionClass("ReflectionClass"); echo $rc; ?> --EXPECT-- -Class [ class ReflectionClass implements Stringable, Reflector ] { +Class [ class ReflectionClass implements Stringable, Reflector, ReflectorWithAttributes ] { - Constants [4] { Constant [ public int IS_IMPLICIT_ABSTRACT ] { 16 } @@ -28,7 +28,7 @@ Class [ class ReflectionClass implements Stringable, Refle Property [ public string $name ] } - - Methods [56] { + - Methods [57] { Method [ private method __clone ] { - Parameters [0] { @@ -434,7 +434,7 @@ Class [ class ReflectionClass implements Stringable, Refle - Tentative return [ string ] } - Method [ public method getAttributes ] { + Method [ public method getAttributes ] { - Parameters [2] { Parameter #0 [ ?string $name = null ] @@ -442,5 +442,14 @@ Class [ class ReflectionClass implements Stringable, Refle } - Return [ array ] } + + Method [ public method getFirstAttribute ] { + + - Parameters [2] { + Parameter #0 [ ?string $name = null ] + Parameter #1 [ int $flags = 0 ] + } + - Return [ ?ReflectionAttribute ] + } } } diff --git a/ext/reflection/tests/ReflectionExtension_getClasses_basic.phpt b/ext/reflection/tests/ReflectionExtension_getClasses_basic.phpt index b7537f170a502..b961336a1a508 100644 --- a/ext/reflection/tests/ReflectionExtension_getClasses_basic.phpt +++ b/ext/reflection/tests/ReflectionExtension_getClasses_basic.phpt @@ -8,7 +8,7 @@ $ext = new ReflectionExtension('reflection'); var_dump($ext->getClasses()); ?> --EXPECT-- -array(25) { +array(26) { ["ReflectionException"]=> object(ReflectionClass)#2 (1) { ["name"]=> @@ -24,113 +24,118 @@ array(25) { ["name"]=> string(9) "Reflector" } - ["ReflectionFunctionAbstract"]=> + ["ReflectorWithAttributes"]=> object(ReflectionClass)#5 (1) { + ["name"]=> + string(23) "ReflectorWithAttributes" + } + ["ReflectionFunctionAbstract"]=> + object(ReflectionClass)#6 (1) { ["name"]=> string(26) "ReflectionFunctionAbstract" } ["ReflectionFunction"]=> - object(ReflectionClass)#6 (1) { + object(ReflectionClass)#7 (1) { ["name"]=> string(18) "ReflectionFunction" } ["ReflectionGenerator"]=> - object(ReflectionClass)#7 (1) { + object(ReflectionClass)#8 (1) { ["name"]=> string(19) "ReflectionGenerator" } ["ReflectionParameter"]=> - object(ReflectionClass)#8 (1) { + object(ReflectionClass)#9 (1) { ["name"]=> string(19) "ReflectionParameter" } ["ReflectionType"]=> - object(ReflectionClass)#9 (1) { + object(ReflectionClass)#10 (1) { ["name"]=> string(14) "ReflectionType" } ["ReflectionNamedType"]=> - object(ReflectionClass)#10 (1) { + object(ReflectionClass)#11 (1) { ["name"]=> string(19) "ReflectionNamedType" } ["ReflectionUnionType"]=> - object(ReflectionClass)#11 (1) { + object(ReflectionClass)#12 (1) { ["name"]=> string(19) "ReflectionUnionType" } ["ReflectionIntersectionType"]=> - object(ReflectionClass)#12 (1) { + object(ReflectionClass)#13 (1) { ["name"]=> string(26) "ReflectionIntersectionType" } ["ReflectionMethod"]=> - object(ReflectionClass)#13 (1) { + object(ReflectionClass)#14 (1) { ["name"]=> string(16) "ReflectionMethod" } ["ReflectionClass"]=> - object(ReflectionClass)#14 (1) { + object(ReflectionClass)#15 (1) { ["name"]=> string(15) "ReflectionClass" } ["ReflectionObject"]=> - object(ReflectionClass)#15 (1) { + object(ReflectionClass)#16 (1) { ["name"]=> string(16) "ReflectionObject" } ["ReflectionProperty"]=> - object(ReflectionClass)#16 (1) { + object(ReflectionClass)#17 (1) { ["name"]=> string(18) "ReflectionProperty" } ["ReflectionClassConstant"]=> - object(ReflectionClass)#17 (1) { + object(ReflectionClass)#18 (1) { ["name"]=> string(23) "ReflectionClassConstant" } ["ReflectionExtension"]=> - object(ReflectionClass)#18 (1) { + object(ReflectionClass)#19 (1) { ["name"]=> string(19) "ReflectionExtension" } ["ReflectionZendExtension"]=> - object(ReflectionClass)#19 (1) { + object(ReflectionClass)#20 (1) { ["name"]=> string(23) "ReflectionZendExtension" } ["ReflectionReference"]=> - object(ReflectionClass)#20 (1) { + object(ReflectionClass)#21 (1) { ["name"]=> string(19) "ReflectionReference" } ["ReflectionAttribute"]=> - object(ReflectionClass)#21 (1) { + object(ReflectionClass)#22 (1) { ["name"]=> string(19) "ReflectionAttribute" } ["ReflectionEnum"]=> - object(ReflectionClass)#22 (1) { + object(ReflectionClass)#23 (1) { ["name"]=> string(14) "ReflectionEnum" } ["ReflectionEnumUnitCase"]=> - object(ReflectionClass)#23 (1) { + object(ReflectionClass)#24 (1) { ["name"]=> string(22) "ReflectionEnumUnitCase" } ["ReflectionEnumBackedCase"]=> - object(ReflectionClass)#24 (1) { + object(ReflectionClass)#25 (1) { ["name"]=> string(24) "ReflectionEnumBackedCase" } ["ReflectionFiber"]=> - object(ReflectionClass)#25 (1) { + object(ReflectionClass)#26 (1) { ["name"]=> string(15) "ReflectionFiber" } ["ReflectionConstant"]=> - object(ReflectionClass)#26 (1) { + object(ReflectionClass)#27 (1) { ["name"]=> string(18) "ReflectionConstant" } diff --git a/ext/reflection/tests/ReflectionFunction_getFirstAttribute.phpt b/ext/reflection/tests/ReflectionFunction_getFirstAttribute.phpt new file mode 100644 index 0000000000000..6ac0b3a305934 --- /dev/null +++ b/ext/reflection/tests/ReflectionFunction_getFirstAttribute.phpt @@ -0,0 +1,34 @@ +--TEST-- +ReflectionFunction::getFirstAttribute() +--FILE-- +getFirstAttribute(AnAttribute::class); +var_dump($attribute); +var_dump($attribute->newInstance()->value); +var_dump($function->getFirstAttribute(AnAttribute::class, ReflectionAttribute::IS_INSTANCEOF)->newInstance()->value); + +$function = new ReflectionFunction('foo'); +var_dump($function->getFirstAttribute(Stringable::class)); +?> +--EXPECT-- +object(ReflectionAttribute)#2 (1) { + ["name"]=> + string(11) "AnAttribute" +} +string(6) "second" +string(5) "first" +NULL