66use PhpParser \Node \Expr \StaticCall ;
77use PHPStan \Analyser \Scope ;
88use PHPStan \DependencyInjection \AutowiredService ;
9+ use PHPStan \Php \PhpVersion ;
910use PHPStan \Reflection \MethodReflection ;
1011use PHPStan \Type \Constant \ConstantBooleanType ;
1112use PHPStan \Type \DynamicStaticMethodReturnTypeExtension ;
13+ use PHPStan \Type \NeverType ;
1214use PHPStan \Type \ObjectType ;
1315use PHPStan \Type \Type ;
1416use Throwable ;
15- use function count ;
16- use function in_array ;
1717
1818#[AutowiredService]
19- final class DateIntervalDynamicReturnTypeExtension
20- implements DynamicStaticMethodReturnTypeExtension
19+ final class DateIntervalDynamicReturnTypeExtension implements DynamicStaticMethodReturnTypeExtension
2120{
2221
22+ public function __construct (private PhpVersion $ phpVersion )
23+ {
24+ }
25+
2326 public function getClass (): string
2427 {
2528 return DateInterval::class;
@@ -40,31 +43,38 @@ public function getTypeFromStaticMethodCall(MethodReflection $methodReflection,
4043
4144 $ strings = $ scope ->getType ($ arguments [0 ]->value )->getConstantStrings ();
4245
43- $ possibleReturnTypes = [];
46+ $ hasFalse = false ;
47+ $ hasDateInterval = false ;
4448 foreach ($ strings as $ string ) {
4549 try {
4650 $ result = @DateInterval::createFromDateString ($ string ->getValue ());
4751 } catch (Throwable ) {
48- $ possibleReturnTypes [] = false ;
49- continue ;
52+ $ result = false ;
5053 }
51- $ possibleReturnTypes [] = $ result instanceof DateInterval ? DateInterval::class : false ;
52- }
5354
54- // the error case, when wrong types are passed
55- if (count ($ possibleReturnTypes ) === 0 ) {
56- return null ;
55+ if ($ result === false ) {
56+ $ hasFalse = true ;
57+ } else {
58+ $ hasDateInterval = true ;
59+ }
5760 }
5861
59- if (in_array (false , $ possibleReturnTypes , true ) && in_array (DateInterval::class, $ possibleReturnTypes , true )) {
62+ if ($ hasFalse ) {
63+ if (!$ hasDateInterval ) {
64+ if ($ this ->phpVersion ->hasDateTimeExceptions ()) {
65+ return new NeverType ();
66+ }
67+
68+ return new ConstantBooleanType (false );
69+ }
70+
6071 return null ;
6172 }
62-
63- if (in_array (false , $ possibleReturnTypes , true )) {
64- return new ConstantBooleanType (false );
73+ if ($ hasDateInterval ) {
74+ return new ObjectType (DateInterval::class);
6575 }
6676
67- return new ObjectType (DateInterval::class) ;
77+ return null ;
6878 }
6979
7080}
0 commit comments