diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 50bcf4cb79c1..d49d4f575e15 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -1314,6 +1314,59 @@ static zend_result read_attributes(zval *ret, HashTable *attributes, zend_class_ } /* }}} */ +static zend_result read_attribute(zval *ret, HashTable *attributes, zend_class_entry *scope, + uint32_t offset, uint32_t target, zend_string *name, zend_class_entry *base, zend_string *filename) /* {{{ */ +{ + ZEND_ASSERT(attributes != NULL); + + zend_attribute *attr; + + if (name) { + // Name based filtering using lowercased key. + zend_string *filter = zend_string_tolower(name); + + ZEND_HASH_PACKED_FOREACH_PTR(attributes, attr) { + if (attr->offset == offset && zend_string_equals(attr->lcname, filter)) { + zend_string_release(filter); + reflection_attribute_factory(ret, attributes, attr, scope, target, filename); + return SUCCESS; + } + } ZEND_HASH_FOREACH_END(); + + zend_string_release(filter); + return SUCCESS; + } + + ZEND_HASH_PACKED_FOREACH_PTR(attributes, attr) { + if (attr->offset != offset) { + continue; + } + + if (base) { + // Base type filtering. + zend_class_entry *ce = zend_lookup_class_ex(attr->name, attr->lcname, 0); + + if (ce == NULL) { + // Bailout on error, otherwise ignore unavailable class. + if (EG(exception)) { + return FAILURE; + } + continue; + } + + if (!instanceof_function(ce, base)) { + continue; + } + } + + reflection_attribute_factory(ret, attributes, attr, scope, target, filename); + return SUCCESS; + } ZEND_HASH_FOREACH_END(); + + return SUCCESS; +} +/* }}} */ + static void reflect_attributes(INTERNAL_FUNCTION_PARAMETERS, HashTable *attributes, uint32_t offset, zend_class_entry *scope, uint32_t target, zend_string *filename) /* {{{ */ { @@ -1354,6 +1407,44 @@ static void reflect_attributes(INTERNAL_FUNCTION_PARAMETERS, HashTable *attribut } /* }}} */ +static void reflect_attribute(INTERNAL_FUNCTION_PARAMETERS, HashTable *attributes, + uint32_t offset, zend_class_entry *scope, uint32_t target, zend_string *filename) /* {{{ */ +{ + zend_string *name = NULL; + zend_long flags = 0; + zend_class_entry *base = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!l", &name, &flags) == FAILURE) { + RETURN_THROWS(); + } + + if (flags & ~REFLECTION_ATTRIBUTE_IS_INSTANCEOF) { + zend_argument_value_error(2, "must be a valid attribute filter flag"); + RETURN_THROWS(); + } + + if (name && (flags & REFLECTION_ATTRIBUTE_IS_INSTANCEOF)) { + if (NULL == (base = zend_lookup_class(name))) { + if (!EG(exception)) { + zend_throw_error(NULL, "Class \"%s\" not found", ZSTR_VAL(name)); + } + + RETURN_THROWS(); + } + + name = NULL; + } + + if (!attributes) { + RETURN_NULL(); + } + + if (FAILURE == read_attribute(return_value, attributes, scope, offset, target, name, base, filename)) { + RETURN_THROWS(); + } +} +/* }}} */ + static void _zend_extension_string(smart_str *str, const zend_extension *extension, const char *indent) /* {{{ */ { smart_str_append_printf(str, "%sZend Extension [ %s ", indent, extension->name); @@ -2063,6 +2154,27 @@ ZEND_METHOD(ReflectionFunctionAbstract, getAttributes) } /* }}} */ +/* {{{ Returns the first matching attribute of this function */ +ZEND_METHOD(ReflectionFunctionAbstract, getAttribute) +{ + reflection_object *intern; + zend_function *fptr; + uint32_t target; + + 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; + } + + reflect_attribute(INTERNAL_FUNCTION_PARAM_PASSTHRU, + fptr->common.attributes, 0, fptr->common.scope, target, + fptr->type == ZEND_USER_FUNCTION ? fptr->op_array.filename : NULL); +} +/* }}} */ + /* {{{ Returns an associative array containing this function's static variables and their values */ ZEND_METHOD(ReflectionFunctionAbstract, getStaticVariables) { @@ -2889,6 +3001,21 @@ ZEND_METHOD(ReflectionParameter, getAttributes) param->fptr->type == ZEND_USER_FUNCTION ? param->fptr->op_array.filename : NULL); } +ZEND_METHOD(ReflectionParameter, getAttribute) +{ + 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_attribute(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); +} + /* {{{ Returns the index of the parameter, starting from 0 */ ZEND_METHOD(ReflectionParameter, getPosition) { @@ -4037,6 +4164,18 @@ ZEND_METHOD(ReflectionClassConstant, getAttributes) } /* }}} */ +ZEND_METHOD(ReflectionClassConstant, getAttribute) +{ + reflection_object *intern; + zend_class_constant *ref; + + GET_REFLECTION_OBJECT_PTR(ref); + + reflect_attribute(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); +} + ZEND_METHOD(ReflectionClassConstant, isEnumCase) { reflection_object *intern; @@ -4442,6 +4581,18 @@ ZEND_METHOD(ReflectionClass, getAttributes) } /* }}} */ +ZEND_METHOD(ReflectionClass, getAttribute) +{ + reflection_object *intern; + zend_class_entry *ce; + + GET_REFLECTION_OBJECT_PTR(ce); + + reflect_attribute(INTERNAL_FUNCTION_PARAM_PASSTHRU, + ce->attributes, 0, ce, ZEND_ATTRIBUTE_TARGET_CLASS, + ce->type == ZEND_USER_CLASS ? ce->info.user.filename : NULL); +} + /* {{{ Returns the class' constructor if there is one, NULL otherwise */ ZEND_METHOD(ReflectionClass, getConstructor) { @@ -6390,6 +6541,22 @@ ZEND_METHOD(ReflectionProperty, getAttributes) } /* }}} */ +ZEND_METHOD(ReflectionProperty, getAttribute) +{ + reflection_object *intern; + property_reference *ref; + + GET_REFLECTION_OBJECT_PTR(ref); + + if (ref->prop == NULL) { + RETURN_NULL(); + } + + reflect_attribute(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); +} + /* {{{ Sets whether non-public properties can be requested */ ZEND_METHOD(ReflectionProperty, setAccessible) { @@ -8148,6 +8315,18 @@ ZEND_METHOD(ReflectionConstant, getAttributes) const_->filename); } +ZEND_METHOD(ReflectionConstant, getAttribute) +{ + reflection_object *intern; + zend_constant *const_; + + GET_REFLECTION_OBJECT_PTR(const_); + + reflect_attribute(INTERNAL_FUNCTION_PARAM_PASSTHRU, + const_->attributes, 0, NULL, ZEND_ATTRIBUTE_TARGET_CONST, + const_->filename); +} + ZEND_METHOD(ReflectionConstant, __toString) { reflection_object *intern; diff --git a/ext/reflection/php_reflection.stub.php b/ext/reflection/php_reflection.stub.php index dd605100f8ba..4b2c9c7bced6 100644 --- a/ext/reflection/php_reflection.stub.php +++ b/ext/reflection/php_reflection.stub.php @@ -115,6 +115,8 @@ public function hasTentativeReturnType(): bool {} public function getTentativeReturnType(): ?ReflectionType {} public function getAttributes(?string $name = null, int $flags = 0): array {} + + public function getAttribute(?string $name = null, int $flags = 0): ?ReflectionAttribute {} } class ReflectionFunction extends ReflectionFunctionAbstract @@ -436,6 +438,8 @@ public function getNamespaceName(): string {} public function getShortName(): string {} public function getAttributes(?string $name = null, int $flags = 0): array {} + + public function getAttribute(?string $name = null, int $flags = 0): ?ReflectionAttribute {} } class ReflectionObject extends ReflectionClass @@ -564,6 +568,8 @@ public function getDefaultValue(): mixed {} public function getAttributes(?string $name = null, int $flags = 0): array {} + public function getAttribute(?string $name = null, int $flags = 0): ?ReflectionAttribute {} + public function hasHooks(): bool {} /** @return array */ @@ -630,6 +636,8 @@ public function getDocComment(): string|false {} public function getAttributes(?string $name = null, int $flags = 0): array {} + public function getAttribute(?string $name = null, int $flags = 0): ?ReflectionAttribute {} + public function isEnumCase(): bool {} public function isDeprecated(): bool {} @@ -720,6 +728,8 @@ public function isVariadic(): bool {} public function isPromoted(): bool {} public function getAttributes(?string $name = null, int $flags = 0): array {} + + public function getAttribute(?string $name = null, int $flags = 0): ?ReflectionAttribute {} } /** @not-serializable */ @@ -940,4 +950,6 @@ public function getExtensionName(): string|false {} public function __toString(): string {} public function getAttributes(?string $name = null, int $flags = 0): array {} + + public function getAttribute(?string $name = null, int $flags = 0): ?ReflectionAttribute {} } diff --git a/ext/reflection/php_reflection_arginfo.h b/ext/reflection/php_reflection_arginfo.h index 65571f38d43c..ef18791f9447 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 php_reflection.stub.php instead. - * Stub hash: c80946cc8c8215bb6527e09bb71b3a97a76a6a98 + * Stub hash: 534c0a7ebdb4bc036d1a9d899e7ca4d75dfe090f * Has decl header: yes */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_Reflection_getModifierNames, 0, 1, IS_ARRAY, 0) @@ -87,6 +87,11 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionFunctionAbstract 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_ReflectionFunctionAbstract_getAttribute, 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_INFO_EX(arginfo_class_ReflectionFunction___construct, 0, 0, 1) ZEND_ARG_OBJ_TYPE_MASK(0, function, Closure, MAY_BE_STRING, NULL) ZEND_END_ARG_INFO() @@ -367,6 +372,8 @@ ZEND_END_ARG_INFO() #define arginfo_class_ReflectionClass_getAttributes arginfo_class_ReflectionFunctionAbstract_getAttributes +#define arginfo_class_ReflectionClass_getAttribute arginfo_class_ReflectionFunctionAbstract_getAttribute + ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ReflectionObject___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, object, IS_OBJECT, 0) ZEND_END_ARG_INFO() @@ -459,6 +466,8 @@ ZEND_END_ARG_INFO() #define arginfo_class_ReflectionProperty_getAttributes arginfo_class_ReflectionFunctionAbstract_getAttributes +#define arginfo_class_ReflectionProperty_getAttribute arginfo_class_ReflectionFunctionAbstract_getAttribute + #define arginfo_class_ReflectionProperty_hasHooks arginfo_class_ReflectionFunctionAbstract_hasTentativeReturnType #define arginfo_class_ReflectionProperty_getHooks arginfo_class_ReflectionFunctionAbstract_getClosureUsedVariables @@ -509,6 +518,8 @@ ZEND_END_ARG_INFO() #define arginfo_class_ReflectionClassConstant_getAttributes arginfo_class_ReflectionFunctionAbstract_getAttributes +#define arginfo_class_ReflectionClassConstant_getAttribute arginfo_class_ReflectionFunctionAbstract_getAttribute + #define arginfo_class_ReflectionClassConstant_isEnumCase arginfo_class_ReflectionFunctionAbstract_hasTentativeReturnType #define arginfo_class_ReflectionClassConstant_isDeprecated arginfo_class_ReflectionFunctionAbstract_hasTentativeReturnType @@ -571,6 +582,8 @@ ZEND_END_ARG_INFO() #define arginfo_class_ReflectionParameter_getAttributes arginfo_class_ReflectionFunctionAbstract_getAttributes +#define arginfo_class_ReflectionParameter_getAttribute arginfo_class_ReflectionFunctionAbstract_getAttribute + #define arginfo_class_ReflectionType___clone arginfo_class_ReflectionFunctionAbstract___clone #define arginfo_class_ReflectionType_allowsNull arginfo_class_ReflectionFunctionAbstract_inNamespace @@ -735,6 +748,8 @@ ZEND_END_ARG_INFO() #define arginfo_class_ReflectionConstant_getAttributes arginfo_class_ReflectionFunctionAbstract_getAttributes +#define arginfo_class_ReflectionConstant_getAttribute arginfo_class_ReflectionFunctionAbstract_getAttribute + ZEND_METHOD(Reflection, getModifierNames); ZEND_METHOD(ReflectionClass, __clone); ZEND_METHOD(ReflectionFunctionAbstract, inNamespace); @@ -768,6 +783,7 @@ ZEND_METHOD(ReflectionFunctionAbstract, getReturnType); ZEND_METHOD(ReflectionFunctionAbstract, hasTentativeReturnType); ZEND_METHOD(ReflectionFunctionAbstract, getTentativeReturnType); ZEND_METHOD(ReflectionFunctionAbstract, getAttributes); +ZEND_METHOD(ReflectionFunctionAbstract, getAttribute); ZEND_METHOD(ReflectionFunction, __construct); ZEND_METHOD(ReflectionFunction, __toString); ZEND_METHOD(ReflectionFunction, isAnonymous); @@ -863,6 +879,7 @@ ZEND_METHOD(ReflectionClass, inNamespace); ZEND_METHOD(ReflectionClass, getNamespaceName); ZEND_METHOD(ReflectionClass, getShortName); ZEND_METHOD(ReflectionClass, getAttributes); +ZEND_METHOD(ReflectionClass, getAttribute); ZEND_METHOD(ReflectionObject, __construct); ZEND_METHOD(ReflectionProperty, __construct); ZEND_METHOD(ReflectionProperty, __toString); @@ -898,6 +915,7 @@ ZEND_METHOD(ReflectionProperty, hasType); ZEND_METHOD(ReflectionProperty, hasDefaultValue); ZEND_METHOD(ReflectionProperty, getDefaultValue); ZEND_METHOD(ReflectionProperty, getAttributes); +ZEND_METHOD(ReflectionProperty, getAttribute); ZEND_METHOD(ReflectionProperty, hasHooks); ZEND_METHOD(ReflectionProperty, getHooks); ZEND_METHOD(ReflectionProperty, hasHook); @@ -917,6 +935,7 @@ ZEND_METHOD(ReflectionClassConstant, getModifiers); ZEND_METHOD(ReflectionClassConstant, getDeclaringClass); ZEND_METHOD(ReflectionClassConstant, getDocComment); ZEND_METHOD(ReflectionClassConstant, getAttributes); +ZEND_METHOD(ReflectionClassConstant, getAttribute); ZEND_METHOD(ReflectionClassConstant, isEnumCase); ZEND_METHOD(ReflectionClassConstant, isDeprecated); ZEND_METHOD(ReflectionClassConstant, hasType); @@ -944,6 +963,7 @@ ZEND_METHOD(ReflectionParameter, getDefaultValueConstantName); ZEND_METHOD(ReflectionParameter, isVariadic); ZEND_METHOD(ReflectionParameter, isPromoted); ZEND_METHOD(ReflectionParameter, getAttributes); +ZEND_METHOD(ReflectionParameter, getAttribute); ZEND_METHOD(ReflectionType, allowsNull); ZEND_METHOD(ReflectionType, __toString); ZEND_METHOD(ReflectionNamedType, getName); @@ -1009,6 +1029,7 @@ ZEND_METHOD(ReflectionConstant, getExtension); ZEND_METHOD(ReflectionConstant, getExtensionName); ZEND_METHOD(ReflectionConstant, __toString); ZEND_METHOD(ReflectionConstant, getAttributes); +ZEND_METHOD(ReflectionConstant, getAttribute); static const zend_function_entry class_Reflection_methods[] = { ZEND_ME(Reflection, getModifierNames, arginfo_class_Reflection_getModifierNames, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) @@ -1048,6 +1069,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, getAttribute, arginfo_class_ReflectionFunctionAbstract_getAttribute, ZEND_ACC_PUBLIC) ZEND_FE_END }; @@ -1161,6 +1183,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, getAttribute, arginfo_class_ReflectionClass_getAttribute, ZEND_ACC_PUBLIC) ZEND_FE_END }; @@ -1205,6 +1228,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, getAttribute, arginfo_class_ReflectionProperty_getAttribute, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionProperty, hasHooks, arginfo_class_ReflectionProperty_hasHooks, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionProperty, getHooks, arginfo_class_ReflectionProperty_getHooks, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionProperty, hasHook, arginfo_class_ReflectionProperty_hasHook, ZEND_ACC_PUBLIC) @@ -1229,6 +1253,7 @@ static const zend_function_entry class_ReflectionClassConstant_methods[] = { 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, getAttribute, arginfo_class_ReflectionClassConstant_getAttribute, 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) @@ -1261,6 +1286,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, getAttribute, arginfo_class_ReflectionParameter_getAttribute, ZEND_ACC_PUBLIC) ZEND_FE_END }; @@ -1383,6 +1409,7 @@ static const zend_function_entry class_ReflectionConstant_methods[] = { ZEND_ME(ReflectionConstant, getExtensionName, arginfo_class_ReflectionConstant_getExtensionName, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionConstant, __toString, arginfo_class_ReflectionConstant___toString, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionConstant, getAttributes, arginfo_class_ReflectionConstant_getAttributes, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionConstant, getAttribute, arginfo_class_ReflectionConstant_getAttribute, ZEND_ACC_PUBLIC) ZEND_FE_END }; diff --git a/ext/reflection/php_reflection_decl.h b/ext/reflection/php_reflection_decl.h index a87e1635419b..896ce1b65b20 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: c80946cc8c8215bb6527e09bb71b3a97a76a6a98 */ + * Stub hash: 534c0a7ebdb4bc036d1a9d899e7ca4d75dfe090f */ -#ifndef ZEND_PHP_REFLECTION_DECL_c80946cc8c8215bb6527e09bb71b3a97a76a6a98_H -#define ZEND_PHP_REFLECTION_DECL_c80946cc8c8215bb6527e09bb71b3a97a76a6a98_H +#ifndef ZEND_PHP_REFLECTION_DECL_534c0a7ebdb4bc036d1a9d899e7ca4d75dfe090f_H +#define ZEND_PHP_REFLECTION_DECL_534c0a7ebdb4bc036d1a9d899e7ca4d75dfe090f_H typedef enum zend_enum_PropertyHookType { ZEND_ENUM_PropertyHookType_Get = 1, ZEND_ENUM_PropertyHookType_Set = 2, } zend_enum_PropertyHookType; -#endif /* ZEND_PHP_REFLECTION_DECL_c80946cc8c8215bb6527e09bb71b3a97a76a6a98_H */ +#endif /* ZEND_PHP_REFLECTION_DECL_534c0a7ebdb4bc036d1a9d899e7ca4d75dfe090f_H */ diff --git a/ext/reflection/tests/ReflectionClassConstant_getAttribute.phpt b/ext/reflection/tests/ReflectionClassConstant_getAttribute.phpt new file mode 100644 index 000000000000..940d3026a587 --- /dev/null +++ b/ext/reflection/tests/ReflectionClassConstant_getAttribute.phpt @@ -0,0 +1,32 @@ +--TEST-- +ReflectionClassConstant::getAttribute() +--FILE-- +getAttribute('Foo')?->getName()); +var_dump($rcc->getAttribute()?->getName()); +var_dump($rcc->getAttribute('Baz')); + +$rcc2 = new ReflectionClassConstant('MyClass', 'PLAIN'); +var_dump($rcc2->getAttribute()); + +?> +--EXPECT-- +string(3) "Foo" +string(3) "Foo" +NULL +NULL diff --git a/ext/reflection/tests/ReflectionClass_getAttribute.phpt b/ext/reflection/tests/ReflectionClass_getAttribute.phpt new file mode 100644 index 000000000000..5e8c9ea0261f --- /dev/null +++ b/ext/reflection/tests/ReflectionClass_getAttribute.phpt @@ -0,0 +1,31 @@ +--TEST-- +ReflectionClass::getAttribute() +--FILE-- +getAttribute('Foo')?->getName()); +var_dump($rc->getAttribute()?->getName()); +var_dump($rc->getAttribute('Baz')); + +// No attributes +class Plain {} +$rc2 = new ReflectionClass('Plain'); +var_dump($rc2->getAttribute()); + +?> +--EXPECT-- +string(3) "Foo" +string(3) "Foo" +NULL +NULL diff --git a/ext/reflection/tests/ReflectionClass_toString_001.phpt b/ext/reflection/tests/ReflectionClass_toString_001.phpt index fd5d83e91741..eb48602b76a2 100644 --- a/ext/reflection/tests/ReflectionClass_toString_001.phpt +++ b/ext/reflection/tests/ReflectionClass_toString_001.phpt @@ -30,7 +30,7 @@ Class [ class ReflectionClass implements Stringable, Refle Property [ public string $name ] } - - Methods [64] { + - Methods [65] { Method [ private method __clone ] { - Parameters [0] { @@ -514,5 +514,14 @@ Class [ class ReflectionClass implements Stringable, Refle } - Return [ array ] } + + Method [ public method getAttribute ] { + + - Parameters [2] { + Parameter #0 [ ?string $name = null ] + Parameter #1 [ int $flags = 0 ] + } + - Return [ ?ReflectionAttribute ] + } } } diff --git a/ext/reflection/tests/ReflectionConstant_getAttribute.phpt b/ext/reflection/tests/ReflectionConstant_getAttribute.phpt new file mode 100644 index 000000000000..14142c72da63 --- /dev/null +++ b/ext/reflection/tests/ReflectionConstant_getAttribute.phpt @@ -0,0 +1,30 @@ +--TEST-- +ReflectionConstant::getAttribute() +--FILE-- +getAttribute('Foo')?->getName()); +var_dump($rc->getAttribute()?->getName()); +var_dump($rc->getAttribute('Baz')); + +// No attributes +const PLAIN = 0; +$rc2 = new ReflectionConstant('PLAIN'); +var_dump($rc2->getAttribute()); + +?> +--EXPECT-- +string(3) "Foo" +string(3) "Foo" +NULL +NULL diff --git a/ext/reflection/tests/ReflectionFunction_getAttribute.phpt b/ext/reflection/tests/ReflectionFunction_getAttribute.phpt new file mode 100644 index 000000000000..fb8dbc9afd7b --- /dev/null +++ b/ext/reflection/tests/ReflectionFunction_getAttribute.phpt @@ -0,0 +1,42 @@ +--TEST-- +ReflectionFunction::getAttribute() and ReflectionMethod::getAttribute() +--FILE-- +getAttribute('Foo')?->getName()); + +// Returns first match when name absent +var_dump($rf->getAttribute()?->getName()); + +// Returns null when no match +var_dump($rf->getAttribute('Baz')); + +// Method +class MyClass { + #[Foo, Bar] + public function myMethod() {} +} + +$rm = new ReflectionMethod('MyClass', 'myMethod'); +var_dump($rm->getAttribute('Bar')?->getName()); +var_dump($rm->getAttribute('Baz')); + +?> +--EXPECT-- +string(3) "Foo" +string(3) "Foo" +NULL +string(3) "Bar" +NULL diff --git a/ext/reflection/tests/ReflectionParameter_getAttribute.phpt b/ext/reflection/tests/ReflectionParameter_getAttribute.phpt new file mode 100644 index 000000000000..abf5929ec5d5 --- /dev/null +++ b/ext/reflection/tests/ReflectionParameter_getAttribute.phpt @@ -0,0 +1,29 @@ +--TEST-- +ReflectionParameter::getAttribute() +--FILE-- +getParameters(); + +$rp = $params[0]; +var_dump($rp->getAttribute('Foo')?->getName()); +var_dump($rp->getAttribute()?->getName()); +var_dump($rp->getAttribute('Baz')); + +$rp2 = $params[1]; +var_dump($rp2->getAttribute()); + +?> +--EXPECT-- +string(3) "Foo" +string(3) "Foo" +NULL +NULL diff --git a/ext/reflection/tests/ReflectionProperty_getAttribute.phpt b/ext/reflection/tests/ReflectionProperty_getAttribute.phpt new file mode 100644 index 000000000000..6a13fe47e6f5 --- /dev/null +++ b/ext/reflection/tests/ReflectionProperty_getAttribute.phpt @@ -0,0 +1,32 @@ +--TEST-- +ReflectionProperty::getAttribute() +--FILE-- +getAttribute('Foo')?->getName()); +var_dump($rp->getAttribute()?->getName()); +var_dump($rp->getAttribute('Baz')); + +$rp2 = new ReflectionProperty('MyClass', 'plain'); +var_dump($rp2->getAttribute()); + +?> +--EXPECT-- +string(3) "Foo" +string(3) "Foo" +NULL +NULL diff --git a/ext/reflection/tests/Reflection_getAttribute_instanceof_flag.phpt b/ext/reflection/tests/Reflection_getAttribute_instanceof_flag.phpt new file mode 100644 index 000000000000..1d79fee47796 --- /dev/null +++ b/ext/reflection/tests/Reflection_getAttribute_instanceof_flag.phpt @@ -0,0 +1,34 @@ +--TEST-- +getAttribute() with ReflectionAttribute::IS_INSTANCEOF flag +--FILE-- +getAttribute('Base', ReflectionAttribute::IS_INSTANCEOF)?->getName()); + +// IS_INSTANCEOF also matches the class itself +var_dump($rf->getAttribute('Child', ReflectionAttribute::IS_INSTANCEOF)?->getName()); + +// Invalid flags raise an error +try { + $rf->getAttribute(null, 99); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +string(5) "Child" +string(5) "Child" +ReflectionFunctionAbstract::getAttribute(): Argument #2 ($flags) must be a valid attribute filter flag