From 7439941d55ea9cf7e1280b6b30f596e34a56512c Mon Sep 17 00:00:00 2001 From: Gabriel Caruso Date: Sun, 31 May 2020 00:17:31 +0200 Subject: [PATCH] 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` Closes GH-5649. --- NEWS | 2 + UPGRADING | 9 ++ 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 +- 8 files changed, 188 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/NEWS b/NEWS index f43f320b25..c4eb3fdbad 100644 --- a/NEWS +++ b/NEWS @@ -139,6 +139,8 @@ PHP NEWS . Fixed bug #69180 (Reflection does not honor trait conflict resolution / method aliasing). (Nikita) . Fixed bug #74939 (Nested traits' aliased methods are lowercased). (Nikita) + . Implement #79628 (Add $filter parameter for ReflectionClass::getConstants + and ReflectionClass::getReflectionConstants) (carusogabriel) - Session: . Fixed bug #78624 (session_gc return value for user defined session diff --git a/UPGRADING b/UPGRADING index 5555786316..f7f4344c6e 100644 --- a/UPGRADING +++ b/UPGRADING @@ -620,6 +620,15 @@ PHP 8.0 UPGRADE NOTES 5. Changed Functions ======================================== +- Reflection: + . ReflectionClass::getConstants and ReflectionClass::getReflectionConstants results + can be now filtered via a new parameter `$filter`. 3 new constants were added to + be used with it: + + ReflectionClassConstant::IS_PUBLIC + ReflectionClassConstant::IS_PROTECTED + ReflectionClassConstant::IS_PRIVATE + - Zip . ZipArchive::addGlob and ZipArchive::addPattern methods accept more values in the "options" array argument: diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 9903863391..e7296b8008 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -4502,33 +4502,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) { @@ -4536,16 +4542,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(); } /* }}} */ @@ -6722,6 +6733,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); @@ -6729,10 +6745,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 e3d3fee52c..49872137a4 100644 --- a/ext/reflection/php_reflection.stub.php +++ b/ext/reflection/php_reflection.stub.php @@ -263,10 +263,10 @@ class ReflectionClass implements Reflector 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 e5ed4742ff..ce3c69de09 100644 --- a/ext/reflection/php_reflection_arginfo.h +++ b/ext/reflection/php_reflection_arginfo.h @@ -194,9 +194,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 0000000000..00dd961b77 --- /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 0000000000..afff6b67ce --- /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 fb39bdb4de..e0860b2005 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 ] } } -- 2.40.0