diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 5a349b28905f3..3b8ad84c89c6c 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -80,6 +80,7 @@ static zend_always_inline zval *reflection_prop_class(zval *object) { /* Class entry pointers */ PHPAPI zend_class_entry *reflector_ptr; +PHPAPI zend_class_entry *reflection_attribute_target_ptr; PHPAPI zend_class_entry *reflection_exception_ptr; PHPAPI zend_class_entry *reflection_ptr; PHPAPI zend_class_entry *reflection_function_abstract_ptr; @@ -146,6 +147,31 @@ typedef struct _type_reference { bool legacy_behavior; } type_reference; +// Based on the target +// TARGET_CLASS: zend_class_entry +// TARGET_FUNCTION: zend_function +// TARGET_METHOD: zend_function +// TARGET_PROPERTY: zend_property_info +// TARGET_CLASS_CONST: zend_class_constant and its name which isn't a part of +// the struct +// TARGET_PARAMETER: target function, closure (or null), and offset +// TARGET_CONST: zend_constant +typedef union _attribute_target_reference { + zend_class_entry *target_class; + zend_function *target_function; + zend_property_info *target_property; + zend_constant *target_const; + struct { + zend_class_constant *constant; + zend_string *name; + } target_class_constant; + struct { + zend_function *target_function; + zval *closure_obj; + uint32_t offset; + } target_parameter; +} attribute_target_reference; + /* Struct for attributes */ typedef struct _attribute_reference { HashTable *attributes; @@ -153,6 +179,7 @@ typedef struct _attribute_reference { zend_class_entry *scope; zend_string *filename; uint32_t target; + attribute_target_reference target_data; } attribute_reference; typedef enum { @@ -1243,7 +1270,7 @@ static void _extension_string(smart_str *str, const zend_module_entry *module, c /* {{{ reflection_attribute_factory */ static void reflection_attribute_factory(zval *object, HashTable *attributes, zend_attribute *data, - zend_class_entry *scope, uint32_t target, zend_string *filename) + zend_class_entry *scope, uint32_t target, zend_string *filename, attribute_target_reference target_data) { reflection_object *intern; attribute_reference *reference; @@ -1256,6 +1283,7 @@ static void reflection_attribute_factory(zval *object, HashTable *attributes, ze reference->scope = scope; reference->filename = filename ? zend_string_copy(filename) : NULL; reference->target = target; + reference->target_data = target_data; intern->ptr = reference; intern->ref_type = REF_TYPE_ATTRIBUTE; ZVAL_STR_COPY(reflection_prop_name(object), data->name); @@ -1263,7 +1291,8 @@ static void reflection_attribute_factory(zval *object, HashTable *attributes, ze /* }}} */ static zend_result 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, + attribute_target_reference target_data) /* {{{ */ { ZEND_ASSERT(attributes != NULL); @@ -1276,7 +1305,7 @@ static zend_result read_attributes(zval *ret, HashTable *attributes, zend_class_ 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(&tmp, attributes, attr, scope, target, filename, target_data); add_next_index_zval(ret, &tmp); } } ZEND_HASH_FOREACH_END(); @@ -1308,7 +1337,7 @@ static zend_result read_attributes(zval *ret, HashTable *attributes, zend_class_ } } - reflection_attribute_factory(&tmp, attributes, attr, scope, target, filename); + reflection_attribute_factory(&tmp, attributes, attr, scope, target, filename, target_data); add_next_index_zval(ret, &tmp); } ZEND_HASH_FOREACH_END(); @@ -1317,7 +1346,8 @@ static zend_result read_attributes(zval *ret, HashTable *attributes, zend_class_ /* }}} */ 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, + attribute_target_reference target_data) /* {{{ */ { zend_string *name = NULL; zend_long flags = 0; @@ -1350,7 +1380,7 @@ static void reflect_attributes(INTERNAL_FUNCTION_PARAMETERS, HashTable *attribut array_init(return_value); - if (FAILURE == read_attributes(return_value, attributes, scope, offset, target, name, base, filename)) { + if (FAILURE == read_attributes(return_value, attributes, scope, offset, target, name, base, filename, target_data)) { RETURN_THROWS(); } } @@ -2059,9 +2089,13 @@ ZEND_METHOD(ReflectionFunctionAbstract, getAttributes) target = ZEND_ATTRIBUTE_TARGET_FUNCTION; } + attribute_target_reference ref; + ref.target_function = fptr; + 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, + ref); } /* }}} */ @@ -2870,9 +2904,14 @@ ZEND_METHOD(ReflectionParameter, getAttributes) HashTable *attributes = param->fptr->common.attributes; zend_class_entry *scope = param->fptr->common.scope; + attribute_target_reference ref; + ref.target_parameter.target_function = param->fptr; + ref.target_parameter.closure_obj = Z_ISUNDEF(intern->obj) ? NULL : &intern->obj; + ref.target_parameter.offset = param->offset; 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, + ref); } /* {{{ Returns the index of the parameter, starting from 0 */ @@ -4004,9 +4043,14 @@ ZEND_METHOD(ReflectionClassConstant, getAttributes) GET_REFLECTION_OBJECT_PTR(ref); + attribute_target_reference ref_details; + ref_details.target_class_constant.constant = ref; + zval *constant_name = reflection_prop_name(ZEND_THIS); + ref_details.target_class_constant.name = zend_string_copy(Z_STR_P(constant_name)); 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, + ref_details); } /* }}} */ @@ -4409,9 +4453,12 @@ ZEND_METHOD(ReflectionClass, getAttributes) GET_REFLECTION_OBJECT_PTR(ce); + attribute_target_reference ref; + ref.target_class = 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); + ce->type == ZEND_USER_CLASS ? ce->info.user.filename : NULL, + ref); } /* }}} */ @@ -6357,9 +6404,12 @@ ZEND_METHOD(ReflectionProperty, getAttributes) RETURN_EMPTY_ARRAY(); } + attribute_target_reference ref_details; + ref_details.target_property = ref->prop; 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, + ref_details); } /* }}} */ @@ -7590,6 +7640,106 @@ ZEND_METHOD(ReflectionAttribute, newInstance) RETURN_COPY_VALUE(&obj); } +ZEND_METHOD(ReflectionAttribute, getCurrent) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_execute_data *prev_ex = EX(prev_execute_data); + + // Previous: attribute constructor + // Previous of that: ZEND_ACC_CALL_VIA_TRAMPOLINE call set up by + // zend_get_attribute_object() to make it look like the call is from + // where the attribute was declared + // Previous of *that*: ReflectionAttribute::newInstance() + if (!prev_ex + || !prev_ex->prev_execute_data + || !prev_ex->prev_execute_data->prev_execute_data + || !prev_ex->prev_execute_data->prev_execute_data->func + ) { + zend_throw_error(NULL, "Current function was not invoked via ReflectionAttribute::newInstance()"); + RETURN_THROWS(); + } + zend_execute_data *caller_context = prev_ex->prev_execute_data->prev_execute_data; + zend_function *caller = caller_context->func; + if (caller->type != ZEND_INTERNAL_FUNCTION) { + zend_throw_error(NULL, "Current function was not invoked via ReflectionAttribute::newInstance()"); + RETURN_THROWS(); + } + zend_internal_function *internal_caller = (zend_internal_function *)caller; + if (internal_caller->handler != zim_ReflectionAttribute_newInstance) { + zend_throw_error(NULL, "Current function was not invoked via ReflectionAttribute::newInstance()"); + RETURN_THROWS(); + } + + zval caller_this = caller_context->This; + ZEND_ASSERT(Z_TYPE(caller_this) == IS_OBJECT); + ZEND_ASSERT(Z_OBJCE(caller_this) == reflection_attribute_ptr); + + reflection_object *intern = Z_REFLECTION_P(&caller_this); + if (intern->ptr == NULL) { + if (EG(exception) && EG(exception)->ce == reflection_exception_ptr) { + RETURN_THROWS(); + } + zend_throw_error(NULL, "Internal error: Failed to retrieve the reflection object"); + RETURN_THROWS(); + } + attribute_reference *attr = intern->ptr; + + switch (attr->target) { + case ZEND_ATTRIBUTE_TARGET_CLASS: + zend_reflection_class_factory(attr->target_data.target_class, return_value); + return; + case ZEND_ATTRIBUTE_TARGET_FUNCTION: + reflection_function_factory(attr->target_data.target_function, NULL, return_value); + return; + case ZEND_ATTRIBUTE_TARGET_METHOD: + reflection_method_factory( + attr->target_data.target_function->common.scope, + attr->target_data.target_function, + NULL, + return_value + ); + return; + case ZEND_ATTRIBUTE_TARGET_PROPERTY: + reflection_property_factory( + attr->target_data.target_property->ce, + attr->target_data.target_property->name, + attr->target_data.target_property, + return_value + ); + return; + case ZEND_ATTRIBUTE_TARGET_CLASS_CONST: + reflection_class_constant_factory( + attr->target_data.target_class_constant.name, + attr->target_data.target_class_constant.constant, + return_value + ); + return; + case ZEND_ATTRIBUTE_TARGET_PARAMETER: { + zend_function *target_function = attr->target_data.target_parameter.target_function; + reflection_parameter_factory( + _copy_function(target_function), + attr->target_data.target_parameter.closure_obj, + target_function->common.arg_info, + attr->target_data.target_parameter.offset, + attr->target_data.target_parameter.offset < target_function->common.required_num_args, + return_value + ); + return; + } + case ZEND_ATTRIBUTE_TARGET_CONST: + object_init_ex(return_value, reflection_constant_ptr); + reflection_object *intern = Z_REFLECTION_P(return_value); + intern->ptr = attr->target_data.target_const; + intern->ref_type = REF_TYPE_OTHER; + zval *name_zv = reflection_prop_name(return_value); + zval_ptr_dtor(name_zv); + ZVAL_STR_COPY(name_zv, attr->target_data.target_const->name); + return; + EMPTY_SWITCH_DEFAULT_CASE() + } +} + ZEND_METHOD(ReflectionEnum, __construct) { reflection_class_object_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); @@ -8111,9 +8261,11 @@ ZEND_METHOD(ReflectionConstant, getAttributes) GET_REFLECTION_OBJECT_PTR(const_); + attribute_target_reference ref; + ref.target_const = const_; reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU, const_->attributes, 0, NULL, ZEND_ATTRIBUTE_TARGET_CONST, - const_->filename); + const_->filename, ref); } ZEND_METHOD(ReflectionConstant, __toString) @@ -8144,7 +8296,9 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */ reflector_ptr = register_class_Reflector(zend_ce_stringable); - reflection_function_abstract_ptr = register_class_ReflectionFunctionAbstract(reflector_ptr); + reflection_attribute_target_ptr = register_class_ReflectionAttributeTarget(reflector_ptr); + + reflection_function_abstract_ptr = register_class_ReflectionFunctionAbstract(reflector_ptr, reflection_attribute_target_ptr); reflection_function_abstract_ptr->default_object_handlers = &reflection_object_handlers; reflection_function_abstract_ptr->create_object = reflection_objects_new; @@ -8156,7 +8310,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, reflection_attribute_target_ptr); reflection_parameter_ptr->create_object = reflection_objects_new; reflection_parameter_ptr->default_object_handlers = &reflection_object_handlers; @@ -8180,7 +8334,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, reflection_attribute_target_ptr); reflection_class_ptr->create_object = reflection_objects_new; reflection_class_ptr->default_object_handlers = &reflection_object_handlers; @@ -8188,11 +8342,11 @@ 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, reflection_attribute_target_ptr); reflection_property_ptr->create_object = reflection_objects_new; reflection_property_ptr->default_object_handlers = &reflection_object_handlers; - reflection_class_constant_ptr = register_class_ReflectionClassConstant(reflector_ptr); + reflection_class_constant_ptr = register_class_ReflectionClassConstant(reflector_ptr, reflection_attribute_target_ptr); reflection_class_constant_ptr->create_object = reflection_objects_new; reflection_class_constant_ptr->default_object_handlers = &reflection_object_handlers; @@ -8228,7 +8382,7 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */ reflection_fiber_ptr->create_object = reflection_objects_new; reflection_fiber_ptr->default_object_handlers = &reflection_object_handlers; - reflection_constant_ptr = register_class_ReflectionConstant(reflector_ptr); + reflection_constant_ptr = register_class_ReflectionConstant(reflector_ptr, reflection_attribute_target_ptr); reflection_constant_ptr->create_object = reflection_objects_new; reflection_constant_ptr->default_object_handlers = &reflection_object_handlers; diff --git a/ext/reflection/php_reflection.h b/ext/reflection/php_reflection.h index dc22407342985..5eb64b46134f1 100644 --- a/ext/reflection/php_reflection.h +++ b/ext/reflection/php_reflection.h @@ -29,6 +29,7 @@ BEGIN_EXTERN_C() /* Class entry pointers */ extern PHPAPI zend_class_entry *reflector_ptr; +extern PHPAPI zend_class_entry *reflection_attribute_target_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 b0273a3174f8e..cfbc38c93b820 100644 --- a/ext/reflection/php_reflection.stub.php +++ b/ext/reflection/php_reflection.stub.php @@ -19,8 +19,13 @@ interface Reflector extends Stringable { } +interface ReflectionAttributeTarget extends Reflector +{ + public function getAttributes(?string $name = null, int $flags = 0): array {} +} + /** @not-serializable */ -abstract class ReflectionFunctionAbstract implements Reflector +abstract class ReflectionFunctionAbstract implements Reflector, ReflectionAttributeTarget { public string $name; @@ -234,7 +239,7 @@ public function setAccessible(bool $accessible): void {} } /** @not-serializable */ -class ReflectionClass implements Reflector +class ReflectionClass implements Reflector, ReflectionAttributeTarget { /** * @cvalue ZEND_ACC_IMPLICIT_ABSTRACT_CLASS @@ -450,7 +455,7 @@ enum PropertyHookType: string } /** @not-serializable */ -class ReflectionProperty implements Reflector +class ReflectionProperty implements Reflector, ReflectionAttributeTarget { /** @cvalue ZEND_ACC_STATIC */ public const int IS_STATIC = UNKNOWN; @@ -581,7 +586,7 @@ public function isWritable(?string $scope, ?object $object = null): bool {} } /** @not-serializable */ -class ReflectionClassConstant implements Reflector +class ReflectionClassConstant implements Reflector, ReflectionAttributeTarget { /** @cvalue ZEND_ACC_PUBLIC */ public const int IS_PUBLIC = UNKNOWN; @@ -640,7 +645,7 @@ public function getType(): ?ReflectionType {} } /** @not-serializable */ -class ReflectionParameter implements Reflector +class ReflectionParameter implements Reflector, ReflectionAttributeTarget { public string $name; @@ -857,6 +862,8 @@ public function __toString(): string {} private function __clone(): void {} private function __construct() {} + + public static function getCurrent(): ReflectionAttributeTarget {} } class ReflectionEnum extends ReflectionClass @@ -911,7 +918,7 @@ public function getTrace(int $options = DEBUG_BACKTRACE_PROVIDE_OBJECT): array { * @strict-properties * @not-serializable */ -class ReflectionConstant implements Reflector +class ReflectionConstant implements Reflector, ReflectionAttributeTarget { public string $name; diff --git a/ext/reflection/php_reflection_arginfo.h b/ext/reflection/php_reflection_arginfo.h index 66605a22bbd66..b3867794a4281 100644 --- a/ext/reflection/php_reflection_arginfo.h +++ b/ext/reflection/php_reflection_arginfo.h @@ -1,11 +1,16 @@ /* This is a generated file, edit php_reflection.stub.php instead. - * Stub hash: 267472e2b726ca5e788eb5cc3e946bc9aa7c9c41 + * Stub hash: 944c68cbea84e2d98c592945f43caec25ba99678 * Has decl header: yes */ 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_ReflectionAttributeTarget_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_TYPE_INFO_EX(arginfo_class_ReflectionFunctionAbstract___clone, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO() @@ -82,10 +87,7 @@ 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_ReflectionAttributeTarget_getAttributes ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ReflectionFunction___construct, 0, 0, 1) ZEND_ARG_OBJ_TYPE_MASK(0, function, Closure, MAY_BE_STRING, NULL) @@ -365,7 +367,7 @@ 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_ReflectionAttributeTarget_getAttributes ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ReflectionObject___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, object, IS_OBJECT, 0) @@ -457,7 +459,7 @@ 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_ReflectionAttributeTarget_getAttributes #define arginfo_class_ReflectionProperty_hasHooks arginfo_class_ReflectionFunctionAbstract_hasTentativeReturnType @@ -507,7 +509,7 @@ 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_getAttributes arginfo_class_ReflectionAttributeTarget_getAttributes #define arginfo_class_ReflectionClassConstant_isEnumCase arginfo_class_ReflectionFunctionAbstract_hasTentativeReturnType @@ -566,7 +568,7 @@ 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_ReflectionAttributeTarget_getAttributes #define arginfo_class_ReflectionType___clone arginfo_class_ReflectionFunctionAbstract___clone @@ -658,6 +660,9 @@ ZEND_END_ARG_INFO() #define arginfo_class_ReflectionAttribute___construct arginfo_class_ReflectionReference___construct +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_ReflectionAttribute_getCurrent, 0, 0, ReflectionAttributeTarget, 0) +ZEND_END_ARG_INFO() + #define arginfo_class_ReflectionEnum___construct arginfo_class_ReflectionClass___construct ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionEnum_hasCase, 0, 1, _IS_BOOL, 0) @@ -731,7 +736,7 @@ ZEND_END_ARG_INFO() #define arginfo_class_ReflectionConstant___toString arginfo_class_ReflectionFunction___toString -#define arginfo_class_ReflectionConstant_getAttributes arginfo_class_ReflectionFunctionAbstract_getAttributes +#define arginfo_class_ReflectionConstant_getAttributes arginfo_class_ReflectionAttributeTarget_getAttributes ZEND_METHOD(Reflection, getModifierNames); ZEND_METHOD(ReflectionClass, __clone); @@ -978,6 +983,7 @@ ZEND_METHOD(ReflectionAttribute, newInstance); ZEND_METHOD(ReflectionAttribute, __toString); ZEND_METHOD(ReflectionAttribute, __clone); ZEND_METHOD(ReflectionAttribute, __construct); +ZEND_METHOD(ReflectionAttribute, getCurrent); ZEND_METHOD(ReflectionEnum, __construct); ZEND_METHOD(ReflectionEnum, hasCase); ZEND_METHOD(ReflectionEnum, getCase); @@ -1012,6 +1018,11 @@ static const zend_function_entry class_Reflection_methods[] = { ZEND_FE_END }; +static const zend_function_entry class_ReflectionAttributeTarget_methods[] = { + ZEND_RAW_FENTRY("getAttributes", NULL, arginfo_class_ReflectionAttributeTarget_getAttributes, 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) @@ -1330,6 +1341,7 @@ static const zend_function_entry class_ReflectionAttribute_methods[] = { 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_ME(ReflectionAttribute, getCurrent, arginfo_class_ReflectionAttribute_getCurrent, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_FE_END }; @@ -1413,13 +1425,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_ReflectionAttributeTarget(zend_class_entry *class_entry_Reflector) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "ReflectionAttributeTarget", class_ReflectionAttributeTarget_methods); + class_entry = zend_register_internal_interface(&ce); + zend_class_implements(class_entry, 1, class_entry_Reflector); + + return class_entry; +} + +static zend_class_entry *register_class_ReflectionFunctionAbstract(zend_class_entry *class_entry_Reflector, zend_class_entry *class_entry_ReflectionAttributeTarget) { zend_class_entry ce, *class_entry; INIT_CLASS_ENTRY(ce, "ReflectionFunctionAbstract", class_ReflectionFunctionAbstract_methods); class_entry = zend_register_internal_class_with_flags(&ce, NULL, 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_ReflectionAttributeTarget); zval property_name_default_value; ZVAL_UNDEF(&property_name_default_value); @@ -1520,13 +1543,13 @@ 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_ReflectionAttributeTarget) { zend_class_entry ce, *class_entry; INIT_CLASS_ENTRY(ce, "ReflectionClass", class_ReflectionClass_methods); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_NOT_SERIALIZABLE); - zend_class_implements(class_entry, 1, class_entry_Reflector); + zend_class_implements(class_entry, 2, class_entry_Reflector, class_entry_ReflectionAttributeTarget); zval const_IS_IMPLICIT_ABSTRACT_value; ZVAL_LONG(&const_IS_IMPLICIT_ABSTRACT_value, ZEND_ACC_IMPLICIT_ABSTRACT_CLASS); @@ -1598,13 +1621,13 @@ static zend_class_entry *register_class_PropertyHookType(void) 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_ReflectionAttributeTarget) { zend_class_entry ce, *class_entry; INIT_CLASS_ENTRY(ce, "ReflectionProperty", class_ReflectionProperty_methods); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_NOT_SERIALIZABLE); - zend_class_implements(class_entry, 1, class_entry_Reflector); + zend_class_implements(class_entry, 2, class_entry_Reflector, class_entry_ReflectionAttributeTarget); zval const_IS_STATIC_value; ZVAL_LONG(&const_IS_STATIC_value, ZEND_ACC_STATIC); @@ -1685,13 +1708,13 @@ static zend_class_entry *register_class_ReflectionProperty(zend_class_entry *cla return class_entry; } -static zend_class_entry *register_class_ReflectionClassConstant(zend_class_entry *class_entry_Reflector) +static zend_class_entry *register_class_ReflectionClassConstant(zend_class_entry *class_entry_Reflector, zend_class_entry *class_entry_ReflectionAttributeTarget) { zend_class_entry ce, *class_entry; INIT_CLASS_ENTRY(ce, "ReflectionClassConstant", class_ReflectionClassConstant_methods); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_NOT_SERIALIZABLE); - zend_class_implements(class_entry, 1, class_entry_Reflector); + zend_class_implements(class_entry, 2, class_entry_Reflector, class_entry_ReflectionAttributeTarget); zval const_IS_PUBLIC_value; ZVAL_LONG(&const_IS_PUBLIC_value, ZEND_ACC_PUBLIC); @@ -1728,13 +1751,13 @@ 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_ReflectionAttributeTarget) { zend_class_entry ce, *class_entry; INIT_CLASS_ENTRY(ce, "ReflectionParameter", class_ReflectionParameter_methods); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_NOT_SERIALIZABLE); - zend_class_implements(class_entry, 1, class_entry_Reflector); + zend_class_implements(class_entry, 2, class_entry_Reflector, class_entry_ReflectionAttributeTarget); zval property_name_default_value; ZVAL_UNDEF(&property_name_default_value); @@ -1905,13 +1928,13 @@ static zend_class_entry *register_class_ReflectionFiber(void) return class_entry; } -static zend_class_entry *register_class_ReflectionConstant(zend_class_entry *class_entry_Reflector) +static zend_class_entry *register_class_ReflectionConstant(zend_class_entry *class_entry_Reflector, zend_class_entry *class_entry_ReflectionAttributeTarget) { zend_class_entry ce, *class_entry; INIT_CLASS_ENTRY(ce, "ReflectionConstant", class_ReflectionConstant_methods); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); - zend_class_implements(class_entry, 1, class_entry_Reflector); + zend_class_implements(class_entry, 2, class_entry_Reflector, class_entry_ReflectionAttributeTarget); zval property_name_default_value; ZVAL_UNDEF(&property_name_default_value); diff --git a/ext/reflection/php_reflection_decl.h b/ext/reflection/php_reflection_decl.h index a5e8affd0beb1..1a6e86e7f6cf6 100644 --- a/ext/reflection/php_reflection_decl.h +++ b/ext/reflection/php_reflection_decl.h @@ -1,12 +1,12 @@ /* This is a generated file, edit php_reflection.stub.php instead. - * Stub hash: 267472e2b726ca5e788eb5cc3e946bc9aa7c9c41 */ + * Stub hash: 944c68cbea84e2d98c592945f43caec25ba99678 */ -#ifndef ZEND_PHP_REFLECTION_DECL_267472e2b726ca5e788eb5cc3e946bc9aa7c9c41_H -#define ZEND_PHP_REFLECTION_DECL_267472e2b726ca5e788eb5cc3e946bc9aa7c9c41_H +#ifndef ZEND_PHP_REFLECTION_DECL_944c68cbea84e2d98c592945f43caec25ba99678_H +#define ZEND_PHP_REFLECTION_DECL_944c68cbea84e2d98c592945f43caec25ba99678_H typedef enum zend_enum_PropertyHookType { ZEND_ENUM_PropertyHookType_Get = 1, ZEND_ENUM_PropertyHookType_Set = 2, } zend_enum_PropertyHookType; -#endif /* ZEND_PHP_REFLECTION_DECL_267472e2b726ca5e788eb5cc3e946bc9aa7c9c41_H */ +#endif /* ZEND_PHP_REFLECTION_DECL_944c68cbea84e2d98c592945f43caec25ba99678_H */ diff --git a/ext/reflection/tests/ReflectionClass_toString_001.phpt b/ext/reflection/tests/ReflectionClass_toString_001.phpt index fd5d83e917419..b6bcc70bcee19 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, ReflectionAttributeTarget ] { - Constants [6] { Constant [ public int IS_IMPLICIT_ABSTRACT ] { 16 } @@ -506,7 +506,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 ] diff --git a/ext/reflection/tests/ReflectionExtension_getClasses_basic.phpt b/ext/reflection/tests/ReflectionExtension_getClasses_basic.phpt index 8ba243a503bd0..a52a2536c99e5 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()); ?> --EXPECTF-- -array(26) { +array(27) { ["ReflectionException"]=> object(ReflectionClass)#%d (1) { ["name"]=> @@ -24,6 +24,11 @@ array(26) { ["name"]=> string(9) "Reflector" } + ["ReflectionAttributeTarget"]=> + object(ReflectionClass)#%d (1) { + ["name"]=> + string(25) "ReflectionAttributeTarget" + } ["ReflectionFunctionAbstract"]=> object(ReflectionClass)#%d (1) { ["name"]=> diff --git a/ext/reflection/tests/attribute_get_current/class.phpt b/ext/reflection/tests/attribute_get_current/class.phpt new file mode 100644 index 0000000000000..9937568f5747f --- /dev/null +++ b/ext/reflection/tests/attribute_get_current/class.phpt @@ -0,0 +1,61 @@ +--TEST-- +ReflectionAttribute::getCurrent() for class +--FILE-- +getAttributes()[0]->newInstance(); + +?> +--EXPECTF-- +Class [ class WithDemo ] { + @@ %s %d-%d + + - Constants [0] { + } + + - Static properties [0] { + } + + - Static methods [0] { + } + + - Properties [0] { + } + + - Methods [0] { + } +} + +Class [ class WithDemo ] { + @@ %s %d-%d + + - Constants [0] { + } + + - Static properties [0] { + } + + - Static methods [0] { + } + + - Properties [0] { + } + + - Methods [0] { + } +} diff --git a/ext/reflection/tests/attribute_get_current/class_constant.phpt b/ext/reflection/tests/attribute_get_current/class_constant.phpt new file mode 100644 index 0000000000000..752d837b5b796 --- /dev/null +++ b/ext/reflection/tests/attribute_get_current/class_constant.phpt @@ -0,0 +1,29 @@ +--TEST-- +ReflectionAttribute::getCurrent() for class constant +--FILE-- +getAttributes()[0]->newInstance(); + +?> +--EXPECT-- +Constant [ public bool EXAMPLE ] { 1 } + +Constant [ public bool EXAMPLE ] { 1 } diff --git a/ext/reflection/tests/attribute_get_current/class_method.phpt b/ext/reflection/tests/attribute_get_current/class_method.phpt new file mode 100644 index 0000000000000..a9cb4e1ed2bfd --- /dev/null +++ b/ext/reflection/tests/attribute_get_current/class_method.phpt @@ -0,0 +1,42 @@ +--TEST-- +ReflectionAttribute::getCurrent() for method +--FILE-- +getAttributes()[0]->newInstance(); + +?> +--EXPECTF-- +Method [ public method method ] { + @@ %s %d - %d + + - Parameters [1] { + Parameter #0 [ mixed $param ] + } +} + +Method [ public method method ] { + @@ %s %d - %d + + - Parameters [1] { + Parameter #0 [ mixed $param ] + } +} diff --git a/ext/reflection/tests/attribute_get_current/class_method_parameter.phpt b/ext/reflection/tests/attribute_get_current/class_method_parameter.phpt new file mode 100644 index 0000000000000..b594975a16e7a --- /dev/null +++ b/ext/reflection/tests/attribute_get_current/class_method_parameter.phpt @@ -0,0 +1,29 @@ +--TEST-- +ReflectionAttribute::getCurrent() for method parameter +--FILE-- +getAttributes()[0]->newInstance(); + +?> +--EXPECT-- +Parameter #0 [ mixed $param ] +Parameter #0 [ mixed $param ] diff --git a/ext/reflection/tests/attribute_get_current/class_property.phpt b/ext/reflection/tests/attribute_get_current/class_property.phpt new file mode 100644 index 0000000000000..0d241dd5d190c --- /dev/null +++ b/ext/reflection/tests/attribute_get_current/class_property.phpt @@ -0,0 +1,29 @@ +--TEST-- +ReflectionAttribute::getCurrent() for property +--FILE-- +getAttributes()[0]->newInstance(); + +?> +--EXPECT-- +Property [ public mixed $prop ] + +Property [ public mixed $prop ] diff --git a/ext/reflection/tests/attribute_get_current/closure.phpt b/ext/reflection/tests/attribute_get_current/closure.phpt new file mode 100644 index 0000000000000..897b5e06eadb5 --- /dev/null +++ b/ext/reflection/tests/attribute_get_current/closure.phpt @@ -0,0 +1,36 @@ +--TEST-- +ReflectionAttribute::getCurrent() for closure +--FILE-- +getAttributes()[0]->newInstance(); + +?> +--EXPECTF-- +Closure [ static function {closure:%s:%d} ] { + @@ %s %d - %d + + - Parameters [1] { + Parameter #0 [ mixed $param ] + } +} + +Closure [ static function {closure:%s:%d} ] { + @@ %s %d - %d + + - Parameters [1] { + Parameter #0 [ mixed $param ] + } +} diff --git a/ext/reflection/tests/attribute_get_current/closure_parameter.phpt b/ext/reflection/tests/attribute_get_current/closure_parameter.phpt new file mode 100644 index 0000000000000..b625eb4e4e66b --- /dev/null +++ b/ext/reflection/tests/attribute_get_current/closure_parameter.phpt @@ -0,0 +1,23 @@ +--TEST-- +ReflectionAttribute::getCurrent() for closure parameter +--FILE-- +getAttributes()[0]->newInstance(); + +?> +--EXPECT-- +Parameter #0 [ mixed $param ] +Parameter #0 [ mixed $param ] diff --git a/ext/reflection/tests/attribute_get_current/global_constant.phpt b/ext/reflection/tests/attribute_get_current/global_constant.phpt new file mode 100644 index 0000000000000..b78c99d6dce70 --- /dev/null +++ b/ext/reflection/tests/attribute_get_current/global_constant.phpt @@ -0,0 +1,25 @@ +--TEST-- +ReflectionAttribute::getCurrent() for global constant +--FILE-- +getAttributes()[0]->newInstance(); + +?> +--EXPECT-- +Constant [ bool GLOBAL_CONSTANT ] { 1 } + +Constant [ bool GLOBAL_CONSTANT ] { 1 } diff --git a/ext/reflection/tests/attribute_get_current/global_function.phpt b/ext/reflection/tests/attribute_get_current/global_function.phpt new file mode 100644 index 0000000000000..34cf38345687b --- /dev/null +++ b/ext/reflection/tests/attribute_get_current/global_function.phpt @@ -0,0 +1,39 @@ +--TEST-- +ReflectionAttribute::getCurrent() for function +--FILE-- +getAttributes()[0]->newInstance(); + +?> +--EXPECTF-- +Function [ function globalFunc ] { + @@ %s %d - %d + + - Parameters [1] { + Parameter #0 [ mixed $param ] + } +} + +Function [ function globalFunc ] { + @@ %s %d - %d + + - Parameters [1] { + Parameter #0 [ mixed $param ] + } +} diff --git a/ext/reflection/tests/attribute_get_current/global_function_parameter.phpt b/ext/reflection/tests/attribute_get_current/global_function_parameter.phpt new file mode 100644 index 0000000000000..cca496f8c3067 --- /dev/null +++ b/ext/reflection/tests/attribute_get_current/global_function_parameter.phpt @@ -0,0 +1,25 @@ +--TEST-- +ReflectionAttribute::getCurrent() for function parameter +--FILE-- +getAttributes()[0]->newInstance(); + +?> +--EXPECT-- +Parameter #0 [ mixed $param ] +Parameter #0 [ mixed $param ]