Skip to content

Commit ca0414e

Browse files
DanielEScherzernielsdos
authored andcommitted
Reflection: show the type of object constants used as default properties
When a property default is based on a global constant, show the type of the default. 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` or `__CLASS__`. Instead, if the default value is an object (`IS_OBJECT`), show the type of that object. Add test cases for both of the `callable` and `__CLASS__` cases to confirm that they now properly show the type of the constant. Closes GH-15902. Closes GH-17781.
1 parent 260e0e9 commit ca0414e

6 files changed

+131
-5
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ PHP NEWS
5151
. Partially fixed bug GH-17387 (Trivial crash in phpdbg lexer). (nielsdos)
5252
. Fix memory leak in phpdbg calling registered function. (nielsdos)
5353

54+
- Reflection:
55+
. Fixed bug GH-15902 (Core dumped in ext/reflection/php_reflection.c).
56+
(DanielEScherzer)
57+
5458
- Streams:
5559
. Fixed bug GH-17650 (realloc with size 0 in user_filters.c). (nielsdos)
5660
. Fix memory leak on overflow in _php_stream_scandir(). (nielsdos)

ext/reflection/php_reflection.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -649,13 +649,20 @@ static int format_default_value(smart_str *str, zval *value) {
649649
} ZEND_HASH_FOREACH_END();
650650
smart_str_appendc(str, ']');
651651
} else if (Z_TYPE_P(value) == IS_OBJECT) {
652-
/* This branch may only be reached for default properties, which don't support arbitrary objects. */
652+
/* This branch is reached if the constant AST was already evaluated and
653+
* resulted in an object; show enum names, or the type of non-enums
654+
* (GH-15902) */
653655
zend_object *obj = Z_OBJ_P(value);
654656
zend_class_entry *class = obj->ce;
655-
ZEND_ASSERT(class->ce_flags & ZEND_ACC_ENUM);
656-
smart_str_append(str, class->name);
657-
smart_str_appends(str, "::");
658-
smart_str_append(str, Z_STR_P(zend_enum_fetch_case_name(obj)));
657+
if (class->ce_flags & ZEND_ACC_ENUM) {
658+
smart_str_append(str, class->name);
659+
smart_str_appends(str, "::");
660+
smart_str_append(str, Z_STR_P(zend_enum_fetch_case_name(obj)));
661+
} else {
662+
smart_str_appends(str, "object(");
663+
smart_str_append(str, class->name);
664+
smart_str_appends(str, ")");
665+
}
659666
} else {
660667
ZEND_ASSERT(Z_TYPE_P(value) == IS_CONSTANT_AST);
661668
zend_string *ast_str = zend_ast_export("", Z_ASTVAL_P(value), "");
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 "callable"
3+
--INI--
4+
opcache.enable_cli=0
5+
--FILE--
6+
<?php
7+
8+
class C {
9+
public stdClass $a = FOO;
10+
}
11+
define('FOO', new stdClass);
12+
13+
new C;
14+
15+
$reflector = new ReflectionClass(C::class);
16+
echo $reflector;
17+
?>
18+
--EXPECTF--
19+
Class [ <user> class C ] {
20+
@@ %sReflectionClass-callable.php %d-%d
21+
22+
- Constants [0] {
23+
}
24+
25+
- Static properties [0] {
26+
}
27+
28+
- Static methods [0] {
29+
}
30+
31+
- Properties [1] {
32+
Property [ public stdClass $a = object(stdClass) ]
33+
}
34+
35+
- Methods [0] {
36+
}
37+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
--TEST--
2+
ReflectionClass object default property - used to say "__CLASS__"
3+
--INI--
4+
opcache.enable_cli=0
5+
--FILE--
6+
<?php
7+
8+
class C {
9+
public stdClass $a = FOO;
10+
}
11+
$reflector = new ReflectionClass(C::class);
12+
13+
define('FOO', new stdClass);
14+
new C;
15+
16+
echo $reflector;
17+
18+
?>
19+
--EXPECTF--
20+
Class [ <user> class C ] {
21+
@@ %sReflectionClass-class.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 = object(stdClass) ]
34+
}
35+
36+
- Methods [0] {
37+
}
38+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
--TEST--
2+
ReflectionProperty object default - used to say "callable"
3+
--INI--
4+
opcache.enable_cli=0
5+
--FILE--
6+
<?php
7+
8+
class C {
9+
public stdClass $a = FOO;
10+
}
11+
define('FOO', new stdClass);
12+
13+
new C;
14+
15+
$reflector = new ReflectionProperty(C::class, 'a');
16+
echo $reflector;
17+
18+
?>
19+
--EXPECTF--
20+
Property [ public stdClass $a = object(stdClass) ]
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
--TEST--
2+
ReflectionProperty object default - used to say "__CLASS__"
3+
--INI--
4+
opcache.enable_cli=0
5+
--FILE--
6+
<?php
7+
8+
class C {
9+
public stdClass $a = FOO;
10+
}
11+
$reflector = new ReflectionProperty(C::class, 'a');
12+
13+
define('FOO', new stdClass);
14+
new C;
15+
16+
echo $reflector;
17+
18+
?>
19+
--EXPECTF--
20+
Property [ public stdClass $a = object(stdClass) ]

0 commit comments

Comments
 (0)