Skip to content

Commit 023ee9c

Browse files
Reflection: show the name of object constants used as default properties
When a property default is based on a global constant, identify and use the name of that constant. Previously, `format_default_value()` assumed that non-scalar and non-array defaults were always going to be `IS_CONSTANT_AST` pointers, and when the AST expression had been evaluated and produced an object, depending on when the `ReflectionClass` or `ReflectionProperty` instance had been created, the default was shown as one of `callable`, `__CLASS__`, or `...`. Instead, if the default value is an object (`IS_OBJECT`), find the name of the `zend_constant` in the global `EG(zend_constants)` that points to the same value, and show that name. If no constant is found, instead of the confusing output of treating the object as an `IS_CONSTANT_AST` value, show `"<Unknown object value>"`. Add test cases for each of the `callable`, `__CLASS__`, and `...` cases to confirm that they all now properly show the name of the constant. Closes gh-15902
1 parent dd0ced3 commit 023ee9c

7 files changed

+192
-0
lines changed

ext/reflection/php_reflection.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,26 @@ static int format_default_value(smart_str *str, zval *value) {
682682
format_default_value(str, zv);
683683
} ZEND_HASH_FOREACH_END();
684684
smart_str_appendc(str, ']');
685+
} else if (Z_TYPE_P(value) == IS_OBJECT) {
686+
// Look through the global constants, GH-15902
687+
zend_constant *constant;
688+
zend_string *name = NULL;
689+
690+
ZEND_HASH_MAP_FOREACH_PTR(EG(zend_constants), constant) {
691+
if (
692+
Z_TYPE(constant->value) == IS_OBJECT &&
693+
Z_OBJ(constant->value) == Z_OBJ_P(value)
694+
) {
695+
// Found the right constant
696+
name = constant->name;
697+
break;
698+
}
699+
} ZEND_HASH_FOREACH_END();
700+
if (name == NULL) {
701+
smart_str_appends(str, "<Unknown object value>");
702+
} else {
703+
smart_str_append(str, name);
704+
}
685705
} else {
686706
ZEND_ASSERT(Z_TYPE_P(value) == IS_CONSTANT_AST);
687707
zend_string *ast_str = zend_ast_export("", Z_ASTVAL_P(value), "");
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--TEST--
2+
ReflectionClass object default property - used to say "callable"
3+
--FILE--
4+
<?php
5+
6+
class C {
7+
public stdClass $a = FOO;
8+
}
9+
define('FOO', new stdClass);
10+
11+
new C;
12+
13+
$reflector = new ReflectionClass(C::class);
14+
var_dump( (string)$reflector );
15+
?>
16+
--EXPECTF--
17+
string(%d) "Class [ <user> class C ] {
18+
@@ %sReflectionClass-callable.php %d-%d
19+
20+
- Constants [0] {
21+
}
22+
23+
- Static properties [0] {
24+
}
25+
26+
- Static methods [0] {
27+
}
28+
29+
- Properties [1] {
30+
Property [ public stdClass $a = FOO ]
31+
}
32+
33+
- Methods [0] {
34+
}
35+
}
36+
"
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
--TEST--
2+
ReflectionClass object default property - used to say "__CLASS__"
3+
--FILE--
4+
<?php
5+
6+
class C {
7+
public stdClass $a = FOO;
8+
}
9+
$reflector = new ReflectionClass(C::class);
10+
11+
define('FOO', new stdClass);
12+
new C;
13+
14+
var_dump( (string)$reflector );
15+
16+
?>
17+
--EXPECTF--
18+
string(%d) "Class [ <user> class C ] {
19+
@@ %sReflectionClass-class.php %d-%d
20+
21+
- Constants [0] {
22+
}
23+
24+
- Static properties [0] {
25+
}
26+
27+
- Static methods [0] {
28+
}
29+
30+
- Properties [1] {
31+
Property [ public stdClass $a = FOO ]
32+
}
33+
34+
- Methods [0] {
35+
}
36+
}
37+
"
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
--TEST--
2+
ReflectionClass object default property - used to say "..."
3+
--FILE--
4+
<?php
5+
6+
class C {
7+
public stdClass $a = FOO;
8+
}
9+
$reflector = new ReflectionClass(C::class);
10+
$c = $reflector->newLazyGhost(function () {});
11+
12+
define('FOO', new stdClass);
13+
14+
$c->a;
15+
16+
var_dump( (string)$reflector );
17+
18+
?>
19+
--EXPECTF--
20+
string(%d) "Class [ <user> class C ] {
21+
@@ %sReflectionClass-dots.php %d-%d
22+
23+
- Constants [0] {
24+
}
25+
26+
- Static properties [0] {
27+
}
28+
29+
- Static methods [0] {
30+
}
31+
32+
- Properties [1] {
33+
Property [ public stdClass $a = FOO ]
34+
}
35+
36+
- Methods [0] {
37+
}
38+
}
39+
"
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
ReflectionProperty object default - used to say "callable"
3+
--FILE--
4+
<?php
5+
6+
class C {
7+
public stdClass $a = FOO;
8+
}
9+
define('FOO', new stdClass);
10+
11+
new C;
12+
13+
$reflector = new ReflectionProperty(C::class, 'a');
14+
var_dump( (string)$reflector );
15+
16+
?>
17+
--EXPECTF--
18+
string(%d) "Property [ public stdClass $a = FOO ]
19+
"
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
ReflectionProperty object default - used to say "__CLASS__"
3+
--FILE--
4+
<?php
5+
6+
class C {
7+
public stdClass $a = FOO;
8+
}
9+
$reflector = new ReflectionProperty(C::class, 'a');
10+
11+
define('FOO', new stdClass);
12+
new C;
13+
14+
var_dump( (string)$reflector );
15+
16+
?>
17+
--EXPECTF--
18+
string(%d) "Property [ public stdClass $a = FOO ]
19+
"
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
ReflectionProperty object default - used to say "..."
3+
--FILE--
4+
<?php
5+
6+
class C {
7+
public stdClass $a = FOO;
8+
}
9+
$reflector = new ReflectionProperty(C::class, 'a');
10+
$lazyFactory = new ReflectionClass(C::class);
11+
$c = $lazyFactory->newLazyGhost(function () {});
12+
13+
define('FOO', new stdClass);
14+
15+
$c->a;
16+
17+
var_dump( (string)$reflector );
18+
19+
?>
20+
--EXPECTF--
21+
string(%d) "Property [ public stdClass $a = FOO ]
22+
"

0 commit comments

Comments
 (0)