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.
This commit is contained in:
Gabriel Caruso 2020-05-31 00:17:31 +02:00
parent 84492f5b50
commit 7439941d55
No known key found for this signature in database
GPG key ID: 4B385A6EE6C9678D
8 changed files with 188 additions and 22 deletions

2
NEWS
View file

@ -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

View file

@ -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:

View file

@ -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);
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) {
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);

View file

@ -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) {}

View file

@ -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

View file

@ -0,0 +1,53 @@
--TEST--
ReflectionClass::getConstants() with $filter
--FILE--
<?php
class A {
public const PUBLIC_CONST = 'BAR';
public const ANOTHER_PUBLIC_CONST = 'BAZ';
protected const PROTECTED_CONST = 'FOO';
private const PRIVATE_CONST = 'QUOZ';
}
class B {
public const PUBLIC_CONST = 'BAR';
protected const ANOTHER_PROTECTED_CONST = 'BAZ';
protected const PROTECTED_CONST = 'FOO';
private const PRIVATE_CONST = 'QUOZ';
}
class C {
public const PUBLIC_CONST = 'BAR';
protected const PROTECTED_CONST = 'FOO';
private const PRIVATE_CONST = 'QUOZ';
private const ANOTHER_PRIVATE_CONST = 'BAZ';
}
$reflectionClassA = new ReflectionClass(A::class);
var_dump($reflectionClassA->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"
}

View file

@ -0,0 +1,83 @@
--TEST--
ReflectionClass::getReflectionConstants() with $filter
--FILE--
<?php
class A {
public const PUBLIC_CONST = 'BAR';
public const ANOTHER_PUBLIC_CONST = 'BAZ';
protected const PROTECTED_CONST = 'FOO';
private const PRIVATE_CONST = 'QUOZ';
}
class B {
public const PUBLIC_CONST = 'BAR';
protected const ANOTHER_PROTECTED_CONST = 'BAZ';
protected const PROTECTED_CONST = 'FOO';
private const PRIVATE_CONST = 'QUOZ';
}
class C {
public const PUBLIC_CONST = 'BAR';
protected const PROTECTED_CONST = 'FOO';
private const PRIVATE_CONST = 'QUOZ';
private const ANOTHER_PRIVATE_CONST = 'BAZ';
}
$reflectionClassA = new ReflectionClass(A::class);
var_dump($reflectionClassA->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"
}
}

View file

@ -165,13 +165,15 @@ Class [ <internal:Reflection> class ReflectionClass implements Reflector, String
Method [ <internal:Reflection> public method getConstants ] {
- Parameters [0] {
- Parameters [1] {
Parameter #0 [ <optional> int $filter = ReflectionClassConstant::IS_PUBLIC | ReflectionClassConstant::IS_PROTECTED | ReflectionClassConstant::IS_PRIVATE ]
}
}
Method [ <internal:Reflection> public method getReflectionConstants ] {
- Parameters [0] {
- Parameters [1] {
Parameter #0 [ <optional> int $filter = ReflectionClassConstant::IS_PUBLIC | ReflectionClassConstant::IS_PROTECTED | ReflectionClassConstant::IS_PRIVATE ]
}
}