Skip to content

Reflection: show the type of object constants used as default properties #17781

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ PHP NEWS
- PHPDBG:
. Fixed bug GH-15901 (phpdbg: Assertion failure on i funcs). (cmb)

- Reflection:
. Fixed bug GH-15902 (Core dumped in ext/reflection/php_reflection.c).
(DanielEScherzer)

- SimpleXML:
. Fixed bug GH-15837 (Segmentation fault in ext/simplexml/simplexml.c).
(nielsdos)
Expand Down
17 changes: 12 additions & 5 deletions ext/reflection/php_reflection.c
Original file line number Diff line number Diff line change
Expand Up @@ -643,13 +643,20 @@ static int format_default_value(smart_str *str, zval *value) {
} ZEND_HASH_FOREACH_END();
smart_str_appendc(str, ']');
} else if (Z_TYPE_P(value) == IS_OBJECT) {
/* This branch may only be reached for default properties, which don't support arbitrary objects. */
/* This branch is reached if the constant AST was already evaluated and
* resulted in an object; show enum names, or the type of non-enums
* (GH-15902) */
zend_object *obj = Z_OBJ_P(value);
zend_class_entry *class = obj->ce;
ZEND_ASSERT(class->ce_flags & ZEND_ACC_ENUM);
smart_str_append(str, class->name);
smart_str_appends(str, "::");
smart_str_append(str, Z_STR_P(zend_enum_fetch_case_name(obj)));
if (class->ce_flags & ZEND_ACC_ENUM) {
smart_str_append(str, class->name);
smart_str_appends(str, "::");
smart_str_append(str, Z_STR_P(zend_enum_fetch_case_name(obj)));
} else {
smart_str_appends(str, "object(");
smart_str_append(str, class->name);
smart_str_appends(str, ")");
}
} else {
ZEND_ASSERT(Z_TYPE_P(value) == IS_CONSTANT_AST);
zend_string *ast_str = zend_ast_export("", Z_ASTVAL_P(value), "");
Expand Down
37 changes: 37 additions & 0 deletions ext/reflection/tests/gh15902/ReflectionClass-callable.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
--TEST--
ReflectionClass object default property - used to say "callable"
--INI--
opcache.enable_cli=0
--FILE--
<?php

class C {
public stdClass $a = FOO;
}
define('FOO', new stdClass);

new C;

$reflector = new ReflectionClass(C::class);
echo $reflector;
?>
--EXPECTF--
Class [ <user> class C ] {
@@ %sReflectionClass-callable.php %d-%d

- Constants [0] {
}

- Static properties [0] {
}

- Static methods [0] {
}

- Properties [1] {
Property [ public stdClass $a = object(stdClass) ]
}

- Methods [0] {
}
}
38 changes: 38 additions & 0 deletions ext/reflection/tests/gh15902/ReflectionClass-class.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
--TEST--
ReflectionClass object default property - used to say "__CLASS__"
--INI--
opcache.enable_cli=0
--FILE--
<?php

class C {
public stdClass $a = FOO;
}
$reflector = new ReflectionClass(C::class);

define('FOO', new stdClass);
new C;

echo $reflector;

?>
--EXPECTF--
Class [ <user> class C ] {
@@ %sReflectionClass-class.php %d-%d

- Constants [0] {
}

- Static properties [0] {
}

- Static methods [0] {
}

- Properties [1] {
Property [ public stdClass $a = object(stdClass) ]
}

- Methods [0] {
}
}
20 changes: 20 additions & 0 deletions ext/reflection/tests/gh15902/ReflectionProperty-callable.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
--TEST--
ReflectionProperty object default - used to say "callable"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this description, why would it say callable? Maybe that's just what it printed for you due to memory corruption?

Copy link
Member Author

@DanielEScherzer DanielEScherzer Feb 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no idea why it would say "callable", but it does - I found that depending on when the reflection object was created it would either say callable or __CLASS__ (or in the case of lazy ghosts, it would say "...")

See my analysis at #15902 (comment)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IS_INDIRECT most likely

--INI--
opcache.enable_cli=0
--FILE--
<?php

class C {
public stdClass $a = FOO;
}
define('FOO', new stdClass);

new C;

$reflector = new ReflectionProperty(C::class, 'a');
echo $reflector;

?>
--EXPECTF--
Property [ public stdClass $a = object(stdClass) ]
20 changes: 20 additions & 0 deletions ext/reflection/tests/gh15902/ReflectionProperty-class.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
--TEST--
ReflectionProperty object default - used to say "__CLASS__"
--INI--
opcache.enable_cli=0
--FILE--
<?php

class C {
public stdClass $a = FOO;
}
$reflector = new ReflectionProperty(C::class, 'a');

define('FOO', new stdClass);
new C;

echo $reflector;

?>
--EXPECTF--
Property [ public stdClass $a = object(stdClass) ]