Skip to content

Commit

Permalink
Add $filter parameter for ReflectionClass::(getConstants|getReflectio…
Browse files Browse the repository at this point in the history
…nConstants)

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.
  • Loading branch information
carusogabriel committed Jun 7, 2020
1 parent 84492f5 commit 7439941
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 22 deletions.
2 changes: 2 additions & 0 deletions NEWS
Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions UPGRADING
Expand Up @@ -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:
Expand Down
47 changes: 31 additions & 16 deletions ext/reflection/php_reflection.c
Expand Up @@ -4502,50 +4502,61 @@ 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)
{
reflection_object *intern;
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();
}
/* }}} */
Expand Down Expand Up @@ -6722,17 +6733,21 @@ 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);
zend_class_implements(reflection_class_constant_ptr, 1, reflector_ptr);
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);
Expand Down
4 changes: 2 additions & 2 deletions ext/reflection/php_reflection.stub.php
Expand Up @@ -263,10 +263,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) {}
Expand Down
6 changes: 4 additions & 2 deletions ext/reflection/php_reflection_arginfo.h
Expand Up @@ -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

Expand Down
53 changes: 53 additions & 0 deletions ext/reflection/tests/ReflectionClass_getConstants_filter.phpt
@@ -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"
}
@@ -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"
}
}
6 changes: 4 additions & 2 deletions ext/reflection/tests/ReflectionClass_toString_001.phpt
Expand Up @@ -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 ]
}
}

Expand Down

0 comments on commit 7439941

Please sign in to comment.