Commit 8b1079a890a for php.net
commit 8b1079a890a55b4865585001a6e5dae4e396ac0b
Author: Derick Rethans <github@derickrethans.nl>
Date: Fri Jul 10 13:38:56 2026 +0100
Fix GH-11310: __debugInfo does nothing on userland classes extending Date classes (#22655)
* Fix GH-11310: __debugInfo does nothing on userland classes extending Date classes
* Add tests to make sure not calling the parent constructor has any effect
diff --git a/NEWS b/NEWS
index 7aada8213bb..2d0abd7eb42 100644
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,8 @@ PHP NEWS
an error). (Derick)
. Fixed Unix timestamps in February of the year 0 are misparsed with
@-notation. (LukasGelbmann)
+ . Fixed bug GH-11310 (__debugInfo does nothing on userland classes extending
+ Date classes). (Derick)
- DBA:
. Fixed OOB read on malformed length field in dba flatfile handler. (alhudz)
diff --git a/ext/date/php_date.c b/ext/date/php_date.c
index 08a91a6318e..e16a61035c5 100644
--- a/ext/date/php_date.c
+++ b/ext/date/php_date.c
@@ -1995,12 +1995,22 @@ static HashTable *date_object_get_properties_for(zend_object *object, zend_prop_
php_date_obj *dateobj;
switch (purpose) {
- case ZEND_PROP_PURPOSE_DEBUG:
case ZEND_PROP_PURPOSE_SERIALIZE:
case ZEND_PROP_PURPOSE_VAR_EXPORT:
case ZEND_PROP_PURPOSE_JSON:
case ZEND_PROP_PURPOSE_ARRAY_CAST:
break;
+ case ZEND_PROP_PURPOSE_DEBUG: {
+ if (object->ce->__debugInfo) {
+ int is_temp = 0;
+ HashTable *ht = zend_std_get_debug_info(object, &is_temp);
+ if (ht && !is_temp) {
+ GC_TRY_ADDREF(ht);
+ }
+ return ht;
+ }
+ break;
+ }
default:
return zend_std_get_properties_for(object, purpose);
}
@@ -2117,12 +2127,22 @@ static HashTable *date_object_get_properties_for_timezone(zend_object *object, z
php_timezone_obj *tzobj;
switch (purpose) {
- case ZEND_PROP_PURPOSE_DEBUG:
case ZEND_PROP_PURPOSE_SERIALIZE:
case ZEND_PROP_PURPOSE_VAR_EXPORT:
case ZEND_PROP_PURPOSE_JSON:
case ZEND_PROP_PURPOSE_ARRAY_CAST:
break;
+ case ZEND_PROP_PURPOSE_DEBUG: {
+ if (object->ce->__debugInfo) {
+ int is_temp = 0;
+ HashTable *ht = zend_std_get_debug_info(object, &is_temp);
+ if (ht && !is_temp) {
+ GC_TRY_ADDREF(ht);
+ }
+ return ht;
+ }
+ break;
+ }
default:
return zend_std_get_properties_for(object, purpose);
}
diff --git a/ext/date/tests/bug-gh11310-1.phpt b/ext/date/tests/bug-gh11310-1.phpt
new file mode 100644
index 00000000000..c12b0201294
--- /dev/null
+++ b/ext/date/tests/bug-gh11310-1.phpt
@@ -0,0 +1,37 @@
+--TEST--
+Bug GH-11310: __debugInfo does nothing on userland classes extending Date classes
+--FILE--
+<?php
+class UDateTime extends DateTime { public function __debugInfo(): array { return ['value' => 'zzz']; } }
+class UDateTimeImmutable extends DateTimeImmutable { public function __debugInfo(): array { return ['value' => 'zzz']; } }
+class UDateTimeZone extends DateTimeZone { public function __debugInfo(): array { return ['value' => 'zzz']; } }
+class UDateInterval extends DateInterval { public function __debugInfo(): array { return ['value' => 'zzz']; } }
+class UDatePeriod extends DatePeriod { public function __debugInfo(): array { return ['value' => 'zzz']; } }
+
+$d = new UDateTime(); var_dump($d);
+$d = new UDateTimeImmutable(); var_dump($d);
+$d = new UDateTimeZone("Europe/Kyiv"); var_dump($d);
+$d = new UDateInterval("P3D"); var_dump($d);
+$d = UDatePeriod::createFromISO8601String("2026-07-09T17:23:06Z/P3D/R5"); var_dump($d);
+?>
+--EXPECTF--
+object(UDateTime)#%d (1) {
+ ["value"]=>
+ string(3) "zzz"
+}
+object(UDateTimeImmutable)#%d (1) {
+ ["value"]=>
+ string(3) "zzz"
+}
+object(UDateTimeZone)#%d (1) {
+ ["value"]=>
+ string(3) "zzz"
+}
+object(UDateInterval)#%d (1) {
+ ["value"]=>
+ string(3) "zzz"
+}
+object(UDatePeriod)#%d (1) {
+ ["value"]=>
+ string(3) "zzz"
+}
diff --git a/ext/date/tests/bug-gh11310-2.phpt b/ext/date/tests/bug-gh11310-2.phpt
new file mode 100644
index 00000000000..8dce510a19d
--- /dev/null
+++ b/ext/date/tests/bug-gh11310-2.phpt
@@ -0,0 +1,37 @@
+--TEST--
+Bug GH-11310: __debugInfo does nothing on userland classes extending Date classes
+--FILE--
+<?php
+class UDateTime extends DateTime { public function __construct() {} public function __debugInfo(): array { return ['value' => 'zzz']; } }
+class UDateTimeImmutable extends DateTimeImmutable { public function __construct() {} public function __debugInfo(): array { return ['value' => 'zzz']; } }
+class UDateTimeZone extends DateTimeZone { public function __construct() {} public function __debugInfo(): array { return ['value' => 'zzz']; } }
+class UDateInterval extends DateInterval { public function __construct() {} public function __debugInfo(): array { return ['value' => 'zzz']; } }
+class UDatePeriod extends DatePeriod { public function __construct() {} public function __debugInfo(): array { return ['value' => 'zzz']; } }
+
+$d = new UDateTime(); var_dump($d);
+$d = new UDateTimeImmutable(); var_dump($d);
+$d = new UDateTimeZone("Europe/Kyiv"); var_dump($d);
+$d = new UDateInterval("P3D"); var_dump($d);
+$d = UDatePeriod::createFromISO8601String("2026-07-09T17:23:06Z/P3D/R5"); var_dump($d);
+?>
+--EXPECTF--
+object(UDateTime)#%d (1) {
+ ["value"]=>
+ string(3) "zzz"
+}
+object(UDateTimeImmutable)#%d (1) {
+ ["value"]=>
+ string(3) "zzz"
+}
+object(UDateTimeZone)#%d (1) {
+ ["value"]=>
+ string(3) "zzz"
+}
+object(UDateInterval)#%d (1) {
+ ["value"]=>
+ string(3) "zzz"
+}
+object(UDatePeriod)#%d (1) {
+ ["value"]=>
+ string(3) "zzz"
+}