Skip to content

Commit

Permalink
Make DateTime::modify() behaviour less annoying
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed May 4, 2022
1 parent b5da7ce commit 7bd9fb7
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 2 deletions.
4 changes: 2 additions & 2 deletions resources/functionMap.php
Expand Up @@ -1604,7 +1604,7 @@
'DateTime::getOffset' => ['int'],
'DateTime::getTimestamp' => ['int'],
'DateTime::getTimezone' => ['DateTimeZone'],
'DateTime::modify' => ['static|false', 'modify'=>'string'],
'DateTime::modify' => ['__benevolent<static|false>', 'modify'=>'string'],
'DateTime::setDate' => ['static', 'year'=>'int', 'month'=>'int', 'day'=>'int'],
'DateTime::setISODate' => ['static', 'year'=>'int', 'week'=>'int', 'day='=>'int'],
'DateTime::setTime' => ['static', 'hour'=>'int', 'minute'=>'int', 'second='=>'int', 'microseconds='=>'int'],
Expand All @@ -1623,7 +1623,7 @@
'DateTimeImmutable::getOffset' => ['int'],
'DateTimeImmutable::getTimestamp' => ['int'],
'DateTimeImmutable::getTimezone' => ['DateTimeZone'],
'DateTimeImmutable::modify' => ['static|false', 'modify'=>'string'],
'DateTimeImmutable::modify' => ['__benevolent<static|false>', 'modify'=>'string'],
'DateTimeImmutable::setDate' => ['static', 'year'=>'int', 'month'=>'int', 'day'=>'int'],
'DateTimeImmutable::setISODate' => ['static', 'year'=>'int', 'week'=>'int', 'day='=>'int'],
'DateTimeImmutable::setTime' => ['static', 'hour'=>'int', 'minute'=>'int', 'second='=>'int', 'microseconds='=>'int'],
Expand Down
32 changes: 32 additions & 0 deletions tests/PHPStan/Analyser/data/bug-6609.php
Expand Up @@ -23,4 +23,36 @@ function modify(\DateTimeInterface $date) {
return $date;
}

/**
* This method should return the same type as a parameter passed.
*
* @template T of \DateTime|\DateTimeImmutable
*
* @param T $date
*
* @return T
*/
function modify2(\DateTimeInterface $date) {
$date = $date->modify('invalidd');
assertType('false', $date);

return $date;
}

/**
* This method should return the same type as a parameter passed.
*
* @template T of \DateTime|\DateTimeImmutable
*
* @param T $date
*
* @return T
*/
function modify3(\DateTimeInterface $date, string $s) {
$date = $date->modify($s);
assertType('(DateTime|DateTimeImmutable|false)', $date);

return $date;
}

}

2 comments on commit 7bd9fb7

@VincentLanglet
Copy link
Contributor

Choose a reason for hiding this comment

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

Hi. What's the idea behind making this benevolent ?
DateTime::createFromFormat returns static|false and not a benevolent union for instance. So why modify is benevolent ?

@ondrejmirtes
Copy link
Member Author

Choose a reason for hiding this comment

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

@VincentLanglet There are situations where the developer know it can never be false, but PHPStan doesn't know that. When I released PHPStan 1.6.6, it became apparent this behaviour is really annoying. In Slevomat's codebase there were dozens of new errors because of this behaviour. For example:

$dateTime->modify(sprintf("+%d days", $this->days));

It can never be false, but PHPStan still thought so. That's why in these cases the union type has to be benevolent. That's why I rushed out PHPStan 1.6.7 last night.

Please sign in to comment.