33namespace PHPStan \Analyser ;
44
55use PhpParser \Node \Name ;
6+ use PHPStan \Php \ComposerPhpVersionFactory ;
67use PHPStan \Php \PhpVersion ;
78use PHPStan \Reflection \NamespaceAnswerer ;
89use PHPStan \Reflection \ReflectionProvider ;
910use PHPStan \Reflection \ReflectionProvider \ReflectionProviderProvider ;
11+ use PHPStan \ShouldNotHappenException ;
1012use PHPStan \Type \Accessory \AccessoryNonFalsyStringType ;
1113use PHPStan \Type \Constant \ConstantFloatType ;
1214use PHPStan \Type \Constant \ConstantIntegerType ;
2123use PHPStan \Type \UnionType ;
2224use function array_key_exists ;
2325use function in_array ;
26+ use function is_array ;
27+ use function is_int ;
2428use function max ;
2529use function sprintf ;
2630use const INF ;
@@ -35,12 +39,13 @@ final class ConstantResolver
3539
3640 /**
3741 * @param string[] $dynamicConstantNames
42+ * @param int|array{min: int, max: int}|null $phpVersion
3843 */
3944 public function __construct (
4045 private ReflectionProviderProvider $ reflectionProviderProvider ,
4146 private array $ dynamicConstantNames ,
42- private ? PhpVersion $ composerMinPhpVersion ,
43- private ? PhpVersion $ composerMaxPhpVersion ,
47+ private int | array | null $ phpVersion ,
48+ private ComposerPhpVersionFactory $ composerPhpVersionFactory ,
4449 )
4550 {
4651 }
@@ -83,15 +88,23 @@ public function resolvePredefinedConstant(string $resolvedConstantName): ?Type
8388 new AccessoryNonFalsyStringType (),
8489 ]);
8590 }
91+
92+ $ minPhpVersion = null ;
93+ $ maxPhpVersion = null ;
94+ if (in_array ($ resolvedConstantName , ['PHP_VERSION_ID ' , 'PHP_MAJOR_VERSION ' , 'PHP_MINOR_VERSION ' , 'PHP_RELEASE_VERSION ' ], true )) {
95+ $ minPhpVersion = $ this ->getMinPhpVersion ();
96+ $ maxPhpVersion = $ this ->getMaxPhpVersion ();
97+ }
98+
8699 if ($ resolvedConstantName === 'PHP_MAJOR_VERSION ' ) {
87100 $ minMajor = 5 ;
88101 $ maxMajor = null ;
89102
90- if ($ this -> composerMinPhpVersion !== null ) {
91- $ minMajor = max ($ minMajor , $ this -> composerMinPhpVersion ->getMajorVersionId ());
103+ if ($ minPhpVersion !== null ) {
104+ $ minMajor = max ($ minMajor , $ minPhpVersion ->getMajorVersionId ());
92105 }
93- if ($ this -> composerMaxPhpVersion !== null ) {
94- $ maxMajor = $ this -> composerMaxPhpVersion ->getMajorVersionId ();
106+ if ($ maxPhpVersion !== null ) {
107+ $ maxMajor = $ maxPhpVersion ->getMajorVersionId ();
95108 }
96109
97110 return $ this ->createInteger ($ minMajor , $ maxMajor );
@@ -101,12 +114,12 @@ public function resolvePredefinedConstant(string $resolvedConstantName): ?Type
101114 $ maxMinor = null ;
102115
103116 if (
104- $ this -> composerMinPhpVersion !== null
105- && $ this -> composerMaxPhpVersion !== null
106- && $ this -> composerMaxPhpVersion -> getMajorVersionId () === $ this -> composerMinPhpVersion ->getMajorVersionId ()
117+ $ minPhpVersion !== null
118+ && $ maxPhpVersion !== null
119+ && $ maxPhpVersion -> getMajorVersionId () === $ minPhpVersion ->getMajorVersionId ()
107120 ) {
108- $ minMinor = $ this -> composerMinPhpVersion ->getMinorVersionId ();
109- $ maxMinor = $ this -> composerMaxPhpVersion ->getMinorVersionId ();
121+ $ minMinor = $ minPhpVersion ->getMinorVersionId ();
122+ $ maxMinor = $ maxPhpVersion ->getMinorVersionId ();
110123 }
111124
112125 return $ this ->createInteger ($ minMinor , $ maxMinor );
@@ -116,25 +129,25 @@ public function resolvePredefinedConstant(string $resolvedConstantName): ?Type
116129 $ maxRelease = null ;
117130
118131 if (
119- $ this -> composerMinPhpVersion !== null
120- && $ this -> composerMaxPhpVersion !== null
121- && $ this -> composerMaxPhpVersion -> getMajorVersionId () === $ this -> composerMinPhpVersion ->getMajorVersionId ()
122- && $ this -> composerMaxPhpVersion -> getMinorVersionId () === $ this -> composerMinPhpVersion ->getMinorVersionId ()
132+ $ minPhpVersion !== null
133+ && $ maxPhpVersion !== null
134+ && $ maxPhpVersion -> getMajorVersionId () === $ minPhpVersion ->getMajorVersionId ()
135+ && $ maxPhpVersion -> getMinorVersionId () === $ minPhpVersion ->getMinorVersionId ()
123136 ) {
124- $ minRelease = $ this -> composerMinPhpVersion ->getPatchVersionId ();
125- $ maxRelease = $ this -> composerMaxPhpVersion ->getPatchVersionId ();
137+ $ minRelease = $ minPhpVersion ->getPatchVersionId ();
138+ $ maxRelease = $ maxPhpVersion ->getPatchVersionId ();
126139 }
127140
128141 return $ this ->createInteger ($ minRelease , $ maxRelease );
129142 }
130143 if ($ resolvedConstantName === 'PHP_VERSION_ID ' ) {
131144 $ minVersion = 50207 ;
132145 $ maxVersion = null ;
133- if ($ this -> composerMinPhpVersion !== null ) {
134- $ minVersion = max ($ minVersion , $ this -> composerMinPhpVersion ->getVersionId ());
146+ if ($ minPhpVersion !== null ) {
147+ $ minVersion = max ($ minVersion , $ minPhpVersion ->getVersionId ());
135148 }
136- if ($ this -> composerMaxPhpVersion !== null ) {
137- $ maxVersion = $ this -> composerMaxPhpVersion ->getVersionId ();
149+ if ($ maxPhpVersion !== null ) {
150+ $ maxVersion = $ maxPhpVersion ->getVersionId ();
138151 }
139152
140153 return $ this ->createInteger ($ minVersion , $ maxVersion );
@@ -351,6 +364,40 @@ public function resolvePredefinedConstant(string $resolvedConstantName): ?Type
351364 return null ;
352365 }
353366
367+ private function getMinPhpVersion (): ?PhpVersion
368+ {
369+ if (is_int ($ this ->phpVersion )) {
370+ return null ;
371+ }
372+
373+ if (is_array ($ this ->phpVersion )) {
374+ if ($ this ->phpVersion ['max ' ] < $ this ->phpVersion ['min ' ]) {
375+ throw new ShouldNotHappenException ('Invalid PHP version range: phpVersion.max should be greater or equal to phpVersion.min. ' );
376+ }
377+
378+ return new PhpVersion ($ this ->phpVersion ['min ' ]);
379+ }
380+
381+ return $ this ->composerPhpVersionFactory ->getMinVersion ();
382+ }
383+
384+ private function getMaxPhpVersion (): ?PhpVersion
385+ {
386+ if (is_int ($ this ->phpVersion )) {
387+ return null ;
388+ }
389+
390+ if (is_array ($ this ->phpVersion )) {
391+ if ($ this ->phpVersion ['max ' ] < $ this ->phpVersion ['min ' ]) {
392+ throw new ShouldNotHappenException ('Invalid PHP version range: phpVersion.max should be greater or equal to phpVersion.min. ' );
393+ }
394+
395+ return new PhpVersion ($ this ->phpVersion ['max ' ]);
396+ }
397+
398+ return $ this ->composerPhpVersionFactory ->getMaxVersion ();
399+ }
400+
354401 public function resolveConstantType (string $ constantName , Type $ constantType ): Type
355402 {
356403 if ($ constantType ->isConstantValue ()->yes () && in_array ($ constantName , $ this ->dynamicConstantNames , true )) {
0 commit comments