Skip to content

Commit 7439941

Browse files
committed
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.
1 parent 84492f5 commit 7439941

8 files changed

+188
-22
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ PHP NEWS
139139
. Fixed bug #69180 (Reflection does not honor trait conflict resolution /
140140
method aliasing). (Nikita)
141141
. Fixed bug #74939 (Nested traits' aliased methods are lowercased). (Nikita)
142+
. Implement #79628 (Add $filter parameter for ReflectionClass::getConstants
143+
and ReflectionClass::getReflectionConstants) (carusogabriel)
142144

143145
- Session:
144146
. Fixed bug #78624 (session_gc return value for user defined session

UPGRADING

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,15 @@ PHP 8.0 UPGRADE NOTES
620620
5. Changed Functions
621621
========================================
622622

623+
- Reflection:
624+
. ReflectionClass::getConstants and ReflectionClass::getReflectionConstants results
625+
can be now filtered via a new parameter `$filter`. 3 new constants were added to
626+
be used with it:
627+
628+
ReflectionClassConstant::IS_PUBLIC
629+
ReflectionClassConstant::IS_PROTECTED
630+
ReflectionClassConstant::IS_PRIVATE
631+
623632
- Zip
624633
. ZipArchive::addGlob and ZipArchive::addPattern methods accept more
625634
values in the "options" array argument:

ext/reflection/php_reflection.c

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4502,50 +4502,61 @@ ZEND_METHOD(ReflectionClass, hasConstant)
45024502
}
45034503
/* }}} */
45044504

4505-
/* {{{ proto public array ReflectionClass::getConstants()
4505+
/* {{{ proto public array ReflectionClass::getConstants([int $filter = ReflectionClassConstant::IS_PUBLIC | ReflectionClassConstant::IS_PROTECTED | ReflectionClassConstant::IS_PRIVATE])
45064506
Returns an associative array containing this class' constants and their values */
45074507
ZEND_METHOD(ReflectionClass, getConstants)
45084508
{
45094509
reflection_object *intern;
45104510
zend_class_entry *ce;
45114511
zend_string *key;
4512-
zend_class_constant *c;
4512+
zend_class_constant *constant;
45134513
zval val;
4514+
zend_long filter = ZEND_ACC_PPP_MASK;
45144515

4515-
if (zend_parse_parameters_none() == FAILURE) {
4516+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &filter) == FAILURE) {
45164517
RETURN_THROWS();
45174518
}
4519+
45184520
GET_REFLECTION_OBJECT_PTR(ce);
4521+
45194522
array_init(return_value);
4520-
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, key, c) {
4521-
if (UNEXPECTED(zval_update_constant_ex(&c->value, ce) != SUCCESS)) {
4523+
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, key, constant) {
4524+
if (UNEXPECTED(zval_update_constant_ex(&constant->value, ce) != SUCCESS)) {
45224525
zend_array_destroy(Z_ARRVAL_P(return_value));
45234526
RETURN_NULL();
45244527
}
4525-
ZVAL_COPY_OR_DUP(&val, &c->value);
4526-
zend_hash_add_new(Z_ARRVAL_P(return_value), key, &val);
4528+
4529+
if (Z_ACCESS_FLAGS(constant->value) & filter) {
4530+
ZVAL_COPY_OR_DUP(&val, &constant->value);
4531+
zend_hash_add_new(Z_ARRVAL_P(return_value), key, &val);
4532+
}
45274533
} ZEND_HASH_FOREACH_END();
45284534
}
45294535
/* }}} */
45304536

4531-
/* {{{ proto public array ReflectionClass::getReflectionConstants()
4537+
/* {{{ proto public ReflectionClassConstant[] ReflectionClass::getReflectionConstants([int $filter = ReflectionClassConstant::IS_PUBLIC | ReflectionClassConstant::IS_PROTECTED | ReflectionClassConstant::IS_PRIVATE])
45324538
Returns an associative array containing this class' constants as ReflectionClassConstant objects */
45334539
ZEND_METHOD(ReflectionClass, getReflectionConstants)
45344540
{
45354541
reflection_object *intern;
45364542
zend_class_entry *ce;
45374543
zend_string *name;
45384544
zend_class_constant *constant;
4545+
zend_long filter = ZEND_ACC_PPP_MASK;
45394546

4540-
if (zend_parse_parameters_none() == FAILURE) {
4547+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &filter) == FAILURE) {
45414548
RETURN_THROWS();
45424549
}
4550+
45434551
GET_REFLECTION_OBJECT_PTR(ce);
4552+
45444553
array_init(return_value);
45454554
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, name, constant) {
4546-
zval class_const;
4547-
reflection_class_constant_factory(name, constant, &class_const);
4548-
zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &class_const);
4555+
if (Z_ACCESS_FLAGS(constant->value) & filter) {
4556+
zval class_const;
4557+
reflection_class_constant_factory(name, constant, &class_const);
4558+
zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &class_const);
4559+
}
45494560
} ZEND_HASH_FOREACH_END();
45504561
}
45514562
/* }}} */
@@ -6722,17 +6733,21 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */
67226733
zend_declare_property_string(reflection_property_ptr, "name", sizeof("name")-1, "", ZEND_ACC_PUBLIC);
67236734
zend_declare_property_string(reflection_property_ptr, "class", sizeof("class")-1, "", ZEND_ACC_PUBLIC);
67246735

6736+
REGISTER_REFLECTION_CLASS_CONST_LONG(property, "IS_STATIC", ZEND_ACC_STATIC);
6737+
REGISTER_REFLECTION_CLASS_CONST_LONG(property, "IS_PUBLIC", ZEND_ACC_PUBLIC);
6738+
REGISTER_REFLECTION_CLASS_CONST_LONG(property, "IS_PROTECTED", ZEND_ACC_PROTECTED);
6739+
REGISTER_REFLECTION_CLASS_CONST_LONG(property, "IS_PRIVATE", ZEND_ACC_PRIVATE);
6740+
67256741
INIT_CLASS_ENTRY(_reflection_entry, "ReflectionClassConstant", class_ReflectionClassConstant_methods);
67266742
reflection_init_class_handlers(&_reflection_entry);
67276743
reflection_class_constant_ptr = zend_register_internal_class(&_reflection_entry);
67286744
zend_class_implements(reflection_class_constant_ptr, 1, reflector_ptr);
67296745
zend_declare_property_string(reflection_class_constant_ptr, "name", sizeof("name")-1, "", ZEND_ACC_PUBLIC);
67306746
zend_declare_property_string(reflection_class_constant_ptr, "class", sizeof("class")-1, "", ZEND_ACC_PUBLIC);
67316747

6732-
REGISTER_REFLECTION_CLASS_CONST_LONG(property, "IS_STATIC", ZEND_ACC_STATIC);
6733-
REGISTER_REFLECTION_CLASS_CONST_LONG(property, "IS_PUBLIC", ZEND_ACC_PUBLIC);
6734-
REGISTER_REFLECTION_CLASS_CONST_LONG(property, "IS_PROTECTED", ZEND_ACC_PROTECTED);
6735-
REGISTER_REFLECTION_CLASS_CONST_LONG(property, "IS_PRIVATE", ZEND_ACC_PRIVATE);
6748+
REGISTER_REFLECTION_CLASS_CONST_LONG(class_constant, "IS_PUBLIC", ZEND_ACC_PUBLIC);
6749+
REGISTER_REFLECTION_CLASS_CONST_LONG(class_constant, "IS_PROTECTED", ZEND_ACC_PROTECTED);
6750+
REGISTER_REFLECTION_CLASS_CONST_LONG(class_constant, "IS_PRIVATE", ZEND_ACC_PRIVATE);
67366751

67376752
INIT_CLASS_ENTRY(_reflection_entry, "ReflectionExtension", class_ReflectionExtension_methods);
67386753
reflection_init_class_handlers(&_reflection_entry);

ext/reflection/php_reflection.stub.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,10 +263,10 @@ public function getProperties(?int $filter = null) {}
263263
public function hasConstant(string $name) {}
264264

265265
/** @return array|null */
266-
public function getConstants() {}
266+
public function getConstants(int $filter = ReflectionClassConstant::IS_PUBLIC | ReflectionClassConstant::IS_PROTECTED | ReflectionClassConstant::IS_PRIVATE) {}
267267

268268
/** @return ReflectionClassConstant[] */
269-
public function getReflectionConstants() {}
269+
public function getReflectionConstants(int $filter = ReflectionClassConstant::IS_PUBLIC | ReflectionClassConstant::IS_PROTECTED | ReflectionClassConstant::IS_PRIVATE) {}
270270

271271
/** @return mixed */
272272
public function getConstant(string $name) {}

ext/reflection/php_reflection_arginfo.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,9 +194,11 @@ ZEND_END_ARG_INFO()
194194

195195
#define arginfo_class_ReflectionClass_hasConstant arginfo_class_ReflectionClass_hasMethod
196196

197-
#define arginfo_class_ReflectionClass_getConstants arginfo_class_ReflectionFunctionAbstract___clone
197+
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ReflectionClass_getConstants, 0, 0, 0)
198+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, filter, IS_LONG, 0, "ReflectionClassConstant::IS_PUBLIC | ReflectionClassConstant::IS_PROTECTED | ReflectionClassConstant::IS_PRIVATE")
199+
ZEND_END_ARG_INFO()
198200

199-
#define arginfo_class_ReflectionClass_getReflectionConstants arginfo_class_ReflectionFunctionAbstract___clone
201+
#define arginfo_class_ReflectionClass_getReflectionConstants arginfo_class_ReflectionClass_getConstants
200202

201203
#define arginfo_class_ReflectionClass_getConstant arginfo_class_ReflectionClass_hasMethod
202204

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
--TEST--
2+
ReflectionClass::getConstants() with $filter
3+
--FILE--
4+
<?php
5+
class A {
6+
public const PUBLIC_CONST = 'BAR';
7+
public const ANOTHER_PUBLIC_CONST = 'BAZ';
8+
protected const PROTECTED_CONST = 'FOO';
9+
private const PRIVATE_CONST = 'QUOZ';
10+
}
11+
12+
class B {
13+
public const PUBLIC_CONST = 'BAR';
14+
protected const ANOTHER_PROTECTED_CONST = 'BAZ';
15+
protected const PROTECTED_CONST = 'FOO';
16+
private const PRIVATE_CONST = 'QUOZ';
17+
}
18+
19+
class C {
20+
public const PUBLIC_CONST = 'BAR';
21+
protected const PROTECTED_CONST = 'FOO';
22+
private const PRIVATE_CONST = 'QUOZ';
23+
private const ANOTHER_PRIVATE_CONST = 'BAZ';
24+
}
25+
26+
$reflectionClassA = new ReflectionClass(A::class);
27+
var_dump($reflectionClassA->getConstants(ReflectionClassConstant::IS_PUBLIC));
28+
29+
$reflectionClassB = new ReflectionClass(B::class);
30+
var_dump($reflectionClassB->getConstants(ReflectionClassConstant::IS_PROTECTED));
31+
32+
$reflectionClassC = new ReflectionClass(C::class);
33+
var_dump($reflectionClassC->getConstants(ReflectionClassConstant::IS_PRIVATE));
34+
?>
35+
--EXPECTF--
36+
array(%d) {
37+
["PUBLIC_CONST"]=>
38+
string(%d) "BAR"
39+
["ANOTHER_PUBLIC_CONST"]=>
40+
string(%d) "BAZ"
41+
}
42+
array(%d) {
43+
["ANOTHER_PROTECTED_CONST"]=>
44+
string(%d) "BAZ"
45+
["PROTECTED_CONST"]=>
46+
string(%d) "FOO"
47+
}
48+
array(%d) {
49+
["PRIVATE_CONST"]=>
50+
string(%d) "QUOZ"
51+
["ANOTHER_PRIVATE_CONST"]=>
52+
string(%d) "BAZ"
53+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
--TEST--
2+
ReflectionClass::getReflectionConstants() with $filter
3+
--FILE--
4+
<?php
5+
class A {
6+
public const PUBLIC_CONST = 'BAR';
7+
public const ANOTHER_PUBLIC_CONST = 'BAZ';
8+
protected const PROTECTED_CONST = 'FOO';
9+
private const PRIVATE_CONST = 'QUOZ';
10+
}
11+
12+
class B {
13+
public const PUBLIC_CONST = 'BAR';
14+
protected const ANOTHER_PROTECTED_CONST = 'BAZ';
15+
protected const PROTECTED_CONST = 'FOO';
16+
private const PRIVATE_CONST = 'QUOZ';
17+
}
18+
19+
class C {
20+
public const PUBLIC_CONST = 'BAR';
21+
protected const PROTECTED_CONST = 'FOO';
22+
private const PRIVATE_CONST = 'QUOZ';
23+
private const ANOTHER_PRIVATE_CONST = 'BAZ';
24+
}
25+
26+
$reflectionClassA = new ReflectionClass(A::class);
27+
var_dump($reflectionClassA->getReflectionConstants(ReflectionClassConstant::IS_PUBLIC));
28+
29+
$reflectionClassB = new ReflectionClass(B::class);
30+
var_dump($reflectionClassB->getReflectionConstants(ReflectionClassConstant::IS_PROTECTED));
31+
32+
$reflectionClassC = new ReflectionClass(C::class);
33+
var_dump($reflectionClassC->getReflectionConstants(ReflectionClassConstant::IS_PRIVATE));
34+
?>
35+
--EXPECTF--
36+
array(2) {
37+
[0]=>
38+
object(ReflectionClassConstant)#%d (%d) {
39+
["name"]=>
40+
string(%d) "PUBLIC_CONST"
41+
["class"]=>
42+
string(%d) "A"
43+
}
44+
[1]=>
45+
object(ReflectionClassConstant)#%d (%d) {
46+
["name"]=>
47+
string(%d) "ANOTHER_PUBLIC_CONST"
48+
["class"]=>
49+
string(%d) "A"
50+
}
51+
}
52+
array(2) {
53+
[0]=>
54+
object(ReflectionClassConstant)#%d (%d) {
55+
["name"]=>
56+
string(%d) "ANOTHER_PROTECTED_CONST"
57+
["class"]=>
58+
string(%d) "B"
59+
}
60+
[1]=>
61+
object(ReflectionClassConstant)#%d (%d) {
62+
["name"]=>
63+
string(%d) "PROTECTED_CONST"
64+
["class"]=>
65+
string(%d) "B"
66+
}
67+
}
68+
array(2) {
69+
[0]=>
70+
object(ReflectionClassConstant)#%d (%d) {
71+
["name"]=>
72+
string(%d) "PRIVATE_CONST"
73+
["class"]=>
74+
string(%d) "C"
75+
}
76+
[1]=>
77+
object(ReflectionClassConstant)#%d (%d) {
78+
["name"]=>
79+
string(%d) "ANOTHER_PRIVATE_CONST"
80+
["class"]=>
81+
string(%d) "C"
82+
}
83+
}

ext/reflection/tests/ReflectionClass_toString_001.phpt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,13 +165,15 @@ Class [ <internal:Reflection> class ReflectionClass implements Reflector, String
165165

166166
Method [ <internal:Reflection> public method getConstants ] {
167167

168-
- Parameters [0] {
168+
- Parameters [1] {
169+
Parameter #0 [ <optional> int $filter = ReflectionClassConstant::IS_PUBLIC | ReflectionClassConstant::IS_PROTECTED | ReflectionClassConstant::IS_PRIVATE ]
169170
}
170171
}
171172

172173
Method [ <internal:Reflection> public method getReflectionConstants ] {
173174

174-
- Parameters [0] {
175+
- Parameters [1] {
176+
Parameter #0 [ <optional> int $filter = ReflectionClassConstant::IS_PUBLIC | ReflectionClassConstant::IS_PROTECTED | ReflectionClassConstant::IS_PRIVATE ]
175177
}
176178
}
177179

0 commit comments

Comments
 (0)