From 5762c8d0b2005ad03cbfc4327851e811ce167ae1 Mon Sep 17 00:00:00 2001 From: Alexander Schwenn Date: Sun, 17 May 2026 18:24:53 +0200 Subject: [PATCH] Fix DateInterval::createFromDateString return type for PHP 8.3+ Since PHP 8.3, DateInterval::createFromDateString() throws DateMalformedIntervalStringException on invalid input instead of returning false. Move the CallMap delta from 8.4 to 8.3 and add a Php83.phpstub override so that both the CallMap and the stub return the correct type. --- dictionaries/CallMap_83.php | 2 +- dictionaries/override/CallMap_83_delta.php | 13 +++++++++++++ dictionaries/override/CallMap_84_delta.php | 13 ------------- src/Psalm/Config.php | 4 ++++ stubs/Php83.phpstub | 11 +++++++++++ tests/CoreStubsTest.php | 21 +++++++++++++++++++++ 6 files changed, 50 insertions(+), 14 deletions(-) create mode 100644 stubs/Php83.phpstub diff --git a/dictionaries/CallMap_83.php b/dictionaries/CallMap_83.php index 6eb9c2cb51a..ecc0c8817cd 100644 --- a/dictionaries/CallMap_83.php +++ b/dictionaries/CallMap_83.php @@ -13170,7 +13170,7 @@ ), 'dateinterval::createfromdatestring' => array ( - 0 => 'DateInterval|false', + 0 => 'DateInterval', 'datetime' => 'string', ), 'dateinterval::format' => diff --git a/dictionaries/override/CallMap_83_delta.php b/dictionaries/override/CallMap_83_delta.php index c420ece8e84..02b110abc4c 100644 --- a/dictionaries/override/CallMap_83_delta.php +++ b/dictionaries/override/CallMap_83_delta.php @@ -28,6 +28,19 @@ 'timezone' => 'DateTimeZone|IntlTimeZone|null|string', ), ), + 'dateinterval::createfromdatestring' => + array ( + 'old' => + array ( + 0 => 'DateInterval|false', + 'datetime' => 'string', + ), + 'new' => + array ( + 0 => 'DateInterval', + 'datetime' => 'string', + ), + ), 'gc_status' => array ( 'old' => diff --git a/dictionaries/override/CallMap_84_delta.php b/dictionaries/override/CallMap_84_delta.php index 39730aadc67..23f7d865205 100644 --- a/dictionaries/override/CallMap_84_delta.php +++ b/dictionaries/override/CallMap_84_delta.php @@ -44,19 +44,6 @@ 'strength' => 'int', ), ), - 'dateinterval::createfromdatestring' => - array ( - 'old' => - array ( - 0 => 'DateInterval|false', - 'datetime' => 'string', - ), - 'new' => - array ( - 0 => 'DateInterval', - 'datetime' => 'string', - ), - ), 'domdocument::registernodeclass' => array ( 'old' => diff --git a/src/Psalm/Config.php b/src/Psalm/Config.php index 59cbeb96607..3e333ae16d9 100644 --- a/src/Psalm/Config.php +++ b/src/Psalm/Config.php @@ -2360,6 +2360,10 @@ public function visitStubFiles(Codebase $codebase, ?Progress $progress = null): $this->php_extensions['random'] = true; // random is a part of the PHP core starting from PHP 8.2 } + if ($codebase->analysis_php_version_id >= 8_03_00) { + $this->internal_stubs[] = $stubsDir . 'Php83.phpstub'; + } + if ($codebase->analysis_php_version_id >= 8_04_00) { $this->internal_stubs[] = $stubsDir . 'Php84.phpstub'; } diff --git a/stubs/Php83.phpstub b/stubs/Php83.phpstub new file mode 100644 index 00000000000..0f6f0abd80e --- /dev/null +++ b/stubs/Php83.phpstub @@ -0,0 +1,11 @@ + ['RedundantCondition'], 'php_version' => '8.0', ]; + yield 'DateInterval::createFromDateString returns DateInterval|false on PHP 8.2' => [ + 'code' => ' [ + '$i' => 'DateInterval|false', + ], + 'ignored_issues' => [], + 'php_version' => '8.2', + ]; + yield 'DateInterval::createFromDateString returns DateInterval on PHP 8.3' => [ + 'code' => 'format("%d");', + 'assertions' => [ + '$i' => 'DateInterval', + ], + 'ignored_issues' => [], + 'php_version' => '8.3', + ]; yield 'sprintf yields a non-empty-string for non-empty-string value' => [ 'code' => '