33namespace  PHPStan \Type \Php ;
44
55use  DateInterval ;
6+ use  DateTimeImmutable ;
67use  PhpParser \Node \Expr \MethodCall ;
78use  PHPStan \Analyser \Scope ;
89use  PHPStan \DependencyInjection \AutowiredService ;
1213use  PHPStan \Type \Accessory \AccessoryNonFalsyStringType ;
1314use  PHPStan \Type \Accessory \AccessoryNumericStringType ;
1415use  PHPStan \Type \Accessory \AccessoryUppercaseStringType ;
16+ use  PHPStan \Type \Constant \ConstantStringType ;
1517use  PHPStan \Type \DynamicMethodReturnTypeExtension ;
1618use  PHPStan \Type \IntersectionType ;
1719use  PHPStan \Type \StringType ;
@@ -55,12 +57,12 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method
5557			return  null ;
5658		}
5759
58- 		// The worst case scenario for the non-falsy-string check is that every number is 0. 
59- 		$ dateIntervalnew  DateInterval ('P0D ' );
60+ 		$ dateInterval$ this referenceDateInterval ();
6061
6162		$ possibleReturnTypes
6263		foreach  ($ constantStringsas  $ string
63- 			$ value$ dateIntervalformat ($ stringgetValue ());
64+ 			$ formatString$ stringgetValue ();
65+ 			$ value$ dateIntervalformat ($ formatString
6466
6567			$ accessories
6668			if  (is_numeric ($ value
@@ -82,10 +84,38 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method
8284				return  null ;
8385			}
8486
85- 			$ possibleReturnTypesnew  IntersectionType ([new  StringType (), ...$ accessories
87+ 			$ possibleReturnTypesnew  IntersectionType ([
88+ 				new  StringType (),
89+ 				...$ this diffInDaysTypes ($ formatString
90+ 				...$ accessories
91+ 			]);
8692		}
8793
8894		return  TypeCombinator::union (...$ possibleReturnTypes
8995	}
9096
97+ 	/** 
98+ 	 * The worst case scenario for the non-falsy-string check is that every number is 0. 
99+ 	 * We create an interval from a difference of two DateTime instances due to the different behavior for %a 
100+ 	 * 
101+ 	 * @see https://www.php.net/manual/en/dateinterval.format.php 
102+ 	 * 
103+ 	 * @return DateInterval 
104+ 	 */ 
105+ 	private  function  referenceDateInterval (): DateInterval 
106+ 	{
107+ 		return  (new  DateTimeImmutable ('@0 ' ))->diff ((new  DateTimeImmutable ('@0 ' )));
108+ 	}
109+ 110+ 	/** 
111+ 	 * @return array<ConstantStringType> 
112+ 	 */ 
113+ 	private  function  diffInDaysTypes (string  $ formatStringarray 
114+ 	{
115+ 		if  ($ formatString'%a ' ) {
116+ 			return  [new  ConstantStringType ('(unknown) ' )];
117+ 		}
118+ 		return  [];
119+ 	}
120+ 91121}
0 commit comments