From 575b05b686f530588a853e35487245ecd41b21a8 Mon Sep 17 00:00:00 2001 From: Gabriel Caruso Date: Sat, 30 May 2020 23:21:39 +0200 Subject: [PATCH 1/2] Fix tests' description for `ReflectionClass::getConstant` --- .../tests/ReflectionClass_getConstant_basic.phpt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ext/reflection/tests/ReflectionClass_getConstant_basic.phpt b/ext/reflection/tests/ReflectionClass_getConstant_basic.phpt index b8906b2070681..67d1eee7e8374 100644 --- a/ext/reflection/tests/ReflectionClass_getConstant_basic.phpt +++ b/ext/reflection/tests/ReflectionClass_getConstant_basic.phpt @@ -1,5 +1,5 @@ --TEST-- -ReflectionClass::getConstants() +ReflectionClass::getConstant() --FILE-- getConstant('a')); var_dump($rc->getConstant('doesnotexist')); } ?> --EXPECT-- -Reflecting on class C: +Reflecting on class C: string(12) "hello from C" bool(false) -Reflecting on class D: +Reflecting on class D: string(12) "hello from C" bool(false) -Reflecting on class E: +Reflecting on class E: string(12) "hello from C" bool(false) -Reflecting on class F: +Reflecting on class F: string(12) "hello from F" bool(false) -Reflecting on class X: +Reflecting on class X: bool(false) bool(false) From 33d15b29b5e38c56bef736544f6f9da376fc7375 Mon Sep 17 00:00:00 2001 From: Gabriel Caruso Date: Sun, 31 May 2020 00:17:31 +0200 Subject: [PATCH 2/2] Add $filter parameter for ReflectionClass::(getConstants|getReflectionConstants) This solves [#79628](https://bugs.php.net/79628). Similar to `ReflectionClass::getMethods()` and `ReflectionClass::getProperties()`, this new `$filter` argument allows the filtering of constants defined in a class by their visibility. For that, we create three new constants for `ReflectionClassConstant`: * `IS_PUBLIC` * `IS_PROTECTED` * `IS_PRIVATE` --- ext/reflection/php_reflection.c | 47 +++++++---- ext/reflection/php_reflection.stub.php | 4 +- ext/reflection/php_reflection_arginfo.h | 6 +- .../ReflectionClass_getConstants_filter.phpt | 53 ++++++++++++ ...onClass_getReflectionConstants_filter.phpt | 83 +++++++++++++++++++ .../tests/ReflectionClass_toString_001.phpt | 6 +- 6 files changed, 177 insertions(+), 22 deletions(-) create mode 100644 ext/reflection/tests/ReflectionClass_getConstants_filter.phpt create mode 100644 ext/reflection/tests/ReflectionClass_getReflectionConstants_filter.phpt diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 9aac065e38bea..f05de3b0a51af 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -4307,33 +4307,39 @@ ZEND_METHOD(ReflectionClass, hasConstant) } /* }}} */ -/* {{{ proto public array ReflectionClass::getConstants() +/* {{{ proto public array ReflectionClass::getConstants([int $filter = ReflectionClassConstant::IS_PUBLIC | ReflectionClassConstant::IS_PROTECTED | ReflectionClassConstant::IS_PRIVATE]) Returns an associative array containing this class' constants and their values */ ZEND_METHOD(ReflectionClass, getConstants) { reflection_object *intern; zend_class_entry *ce; zend_string *key; - zend_class_constant *c; + zend_class_constant *constant; zval val; + zend_long filter = ZEND_ACC_PPP_MASK; - if (zend_parse_parameters_none() == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &filter) == FAILURE) { RETURN_THROWS(); } + GET_REFLECTION_OBJECT_PTR(ce); + array_init(return_value); - ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, key, c) { - if (UNEXPECTED(zval_update_constant_ex(&c->value, ce) != SUCCESS)) { + ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, key, constant) { + if (UNEXPECTED(zval_update_constant_ex(&constant->value, ce) != SUCCESS)) { zend_array_destroy(Z_ARRVAL_P(return_value)); RETURN_NULL(); } - ZVAL_COPY_OR_DUP(&val, &c->value); - zend_hash_add_new(Z_ARRVAL_P(return_value), key, &val); + + if (Z_ACCESS_FLAGS(constant->value) & filter) { + ZVAL_COPY_OR_DUP(&val, &constant->value); + zend_hash_add_new(Z_ARRVAL_P(return_value), key, &val); + } } ZEND_HASH_FOREACH_END(); } /* }}} */ -/* {{{ proto public array ReflectionClass::getReflectionConstants() +/* {{{ proto public ReflectionClassConstant[] ReflectionClass::getReflectionConstants([int $filter = ReflectionClassConstant::IS_PUBLIC | ReflectionClassConstant::IS_PROTECTED | ReflectionClassConstant::IS_PRIVATE]) Returns an associative array containing this class' constants as ReflectionClassConstant objects */ ZEND_METHOD(ReflectionClass, getReflectionConstants) { @@ -4341,16 +4347,21 @@ ZEND_METHOD(ReflectionClass, getReflectionConstants) zend_class_entry *ce; zend_string *name; zend_class_constant *constant; + zend_long filter = ZEND_ACC_PPP_MASK; - if (zend_parse_parameters_none() == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &filter) == FAILURE) { RETURN_THROWS(); } + GET_REFLECTION_OBJECT_PTR(ce); + array_init(return_value); ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, name, constant) { - zval class_const; - reflection_class_constant_factory(name, constant, &class_const); - zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &class_const); + if (Z_ACCESS_FLAGS(constant->value) & filter) { + zval class_const; + reflection_class_constant_factory(name, constant, &class_const); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &class_const); + } } ZEND_HASH_FOREACH_END(); } /* }}} */ @@ -6311,6 +6322,11 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */ zend_declare_property_string(reflection_property_ptr, "name", sizeof("name")-1, "", ZEND_ACC_PUBLIC); zend_declare_property_string(reflection_property_ptr, "class", sizeof("class")-1, "", ZEND_ACC_PUBLIC); + REGISTER_REFLECTION_CLASS_CONST_LONG(property, "IS_STATIC", ZEND_ACC_STATIC); + REGISTER_REFLECTION_CLASS_CONST_LONG(property, "IS_PUBLIC", ZEND_ACC_PUBLIC); + REGISTER_REFLECTION_CLASS_CONST_LONG(property, "IS_PROTECTED", ZEND_ACC_PROTECTED); + REGISTER_REFLECTION_CLASS_CONST_LONG(property, "IS_PRIVATE", ZEND_ACC_PRIVATE); + INIT_CLASS_ENTRY(_reflection_entry, "ReflectionClassConstant", class_ReflectionClassConstant_methods); reflection_init_class_handlers(&_reflection_entry); reflection_class_constant_ptr = zend_register_internal_class(&_reflection_entry); @@ -6318,10 +6334,9 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */ zend_declare_property_string(reflection_class_constant_ptr, "name", sizeof("name")-1, "", ZEND_ACC_PUBLIC); zend_declare_property_string(reflection_class_constant_ptr, "class", sizeof("class")-1, "", ZEND_ACC_PUBLIC); - REGISTER_REFLECTION_CLASS_CONST_LONG(property, "IS_STATIC", ZEND_ACC_STATIC); - REGISTER_REFLECTION_CLASS_CONST_LONG(property, "IS_PUBLIC", ZEND_ACC_PUBLIC); - REGISTER_REFLECTION_CLASS_CONST_LONG(property, "IS_PROTECTED", ZEND_ACC_PROTECTED); - REGISTER_REFLECTION_CLASS_CONST_LONG(property, "IS_PRIVATE", ZEND_ACC_PRIVATE); + REGISTER_REFLECTION_CLASS_CONST_LONG(class_constant, "IS_PUBLIC", ZEND_ACC_PUBLIC); + REGISTER_REFLECTION_CLASS_CONST_LONG(class_constant, "IS_PROTECTED", ZEND_ACC_PROTECTED); + REGISTER_REFLECTION_CLASS_CONST_LONG(class_constant, "IS_PRIVATE", ZEND_ACC_PRIVATE); INIT_CLASS_ENTRY(_reflection_entry, "ReflectionExtension", class_ReflectionExtension_methods); reflection_init_class_handlers(&_reflection_entry); diff --git a/ext/reflection/php_reflection.stub.php b/ext/reflection/php_reflection.stub.php index 30627475073b4..915a4900cceb6 100644 --- a/ext/reflection/php_reflection.stub.php +++ b/ext/reflection/php_reflection.stub.php @@ -260,10 +260,10 @@ public function getProperties(?int $filter = null) {} public function hasConstant(string $name) {} /** @return array|null */ - public function getConstants() {} + public function getConstants(int $filter = ReflectionClassConstant::IS_PUBLIC | ReflectionClassConstant::IS_PROTECTED | ReflectionClassConstant::IS_PRIVATE) {} /** @return ReflectionClassConstant[] */ - public function getReflectionConstants() {} + public function getReflectionConstants(int $filter = ReflectionClassConstant::IS_PUBLIC | ReflectionClassConstant::IS_PROTECTED | ReflectionClassConstant::IS_PRIVATE) {} /** @return mixed */ public function getConstant(string $name) {} diff --git a/ext/reflection/php_reflection_arginfo.h b/ext/reflection/php_reflection_arginfo.h index 1e3e9988deee0..ff78d61774a65 100644 --- a/ext/reflection/php_reflection_arginfo.h +++ b/ext/reflection/php_reflection_arginfo.h @@ -189,9 +189,11 @@ ZEND_END_ARG_INFO() #define arginfo_class_ReflectionClass_hasConstant arginfo_class_ReflectionClass_hasMethod -#define arginfo_class_ReflectionClass_getConstants arginfo_class_ReflectionFunctionAbstract___clone +ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ReflectionClass_getConstants, 0, 0, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, filter, IS_LONG, 0, "ReflectionClassConstant::IS_PUBLIC | ReflectionClassConstant::IS_PROTECTED | ReflectionClassConstant::IS_PRIVATE") +ZEND_END_ARG_INFO() -#define arginfo_class_ReflectionClass_getReflectionConstants arginfo_class_ReflectionFunctionAbstract___clone +#define arginfo_class_ReflectionClass_getReflectionConstants arginfo_class_ReflectionClass_getConstants #define arginfo_class_ReflectionClass_getConstant arginfo_class_ReflectionClass_hasMethod diff --git a/ext/reflection/tests/ReflectionClass_getConstants_filter.phpt b/ext/reflection/tests/ReflectionClass_getConstants_filter.phpt new file mode 100644 index 0000000000000..00dd961b77579 --- /dev/null +++ b/ext/reflection/tests/ReflectionClass_getConstants_filter.phpt @@ -0,0 +1,53 @@ +--TEST-- +ReflectionClass::getConstants() with $filter +--FILE-- +getConstants(ReflectionClassConstant::IS_PUBLIC)); + +$reflectionClassB = new ReflectionClass(B::class); +var_dump($reflectionClassB->getConstants(ReflectionClassConstant::IS_PROTECTED)); + +$reflectionClassC = new ReflectionClass(C::class); +var_dump($reflectionClassC->getConstants(ReflectionClassConstant::IS_PRIVATE)); +?> +--EXPECTF-- +array(%d) { + ["PUBLIC_CONST"]=> + string(%d) "BAR" + ["ANOTHER_PUBLIC_CONST"]=> + string(%d) "BAZ" +} +array(%d) { + ["ANOTHER_PROTECTED_CONST"]=> + string(%d) "BAZ" + ["PROTECTED_CONST"]=> + string(%d) "FOO" +} +array(%d) { + ["PRIVATE_CONST"]=> + string(%d) "QUOZ" + ["ANOTHER_PRIVATE_CONST"]=> + string(%d) "BAZ" +} diff --git a/ext/reflection/tests/ReflectionClass_getReflectionConstants_filter.phpt b/ext/reflection/tests/ReflectionClass_getReflectionConstants_filter.phpt new file mode 100644 index 0000000000000..afff6b67ce072 --- /dev/null +++ b/ext/reflection/tests/ReflectionClass_getReflectionConstants_filter.phpt @@ -0,0 +1,83 @@ +--TEST-- +ReflectionClass::getReflectionConstants() with $filter +--FILE-- +getReflectionConstants(ReflectionClassConstant::IS_PUBLIC)); + +$reflectionClassB = new ReflectionClass(B::class); +var_dump($reflectionClassB->getReflectionConstants(ReflectionClassConstant::IS_PROTECTED)); + +$reflectionClassC = new ReflectionClass(C::class); +var_dump($reflectionClassC->getReflectionConstants(ReflectionClassConstant::IS_PRIVATE)); +?> +--EXPECTF-- +array(2) { + [0]=> + object(ReflectionClassConstant)#%d (%d) { + ["name"]=> + string(%d) "PUBLIC_CONST" + ["class"]=> + string(%d) "A" + } + [1]=> + object(ReflectionClassConstant)#%d (%d) { + ["name"]=> + string(%d) "ANOTHER_PUBLIC_CONST" + ["class"]=> + string(%d) "A" + } +} +array(2) { + [0]=> + object(ReflectionClassConstant)#%d (%d) { + ["name"]=> + string(%d) "ANOTHER_PROTECTED_CONST" + ["class"]=> + string(%d) "B" + } + [1]=> + object(ReflectionClassConstant)#%d (%d) { + ["name"]=> + string(%d) "PROTECTED_CONST" + ["class"]=> + string(%d) "B" + } +} +array(2) { + [0]=> + object(ReflectionClassConstant)#%d (%d) { + ["name"]=> + string(%d) "PRIVATE_CONST" + ["class"]=> + string(%d) "C" + } + [1]=> + object(ReflectionClassConstant)#%d (%d) { + ["name"]=> + string(%d) "ANOTHER_PRIVATE_CONST" + ["class"]=> + string(%d) "C" + } +} diff --git a/ext/reflection/tests/ReflectionClass_toString_001.phpt b/ext/reflection/tests/ReflectionClass_toString_001.phpt index 367645d019d5d..8821c03683c77 100644 --- a/ext/reflection/tests/ReflectionClass_toString_001.phpt +++ b/ext/reflection/tests/ReflectionClass_toString_001.phpt @@ -165,13 +165,15 @@ Class [ class ReflectionClass implements Reflector, String Method [ public method getConstants ] { - - Parameters [0] { + - Parameters [1] { + Parameter #0 [ int $filter = ReflectionClassConstant::IS_PUBLIC | ReflectionClassConstant::IS_PROTECTED | ReflectionClassConstant::IS_PRIVATE ] } } Method [ public method getReflectionConstants ] { - - Parameters [0] { + - Parameters [1] { + Parameter #0 [ int $filter = ReflectionClassConstant::IS_PUBLIC | ReflectionClassConstant::IS_PROTECTED | ReflectionClassConstant::IS_PRIVATE ] } }