|
123 | 123 | use function is_string; |
124 | 124 | use function ltrim; |
125 | 125 | use function md5; |
| 126 | +use function min; |
126 | 127 | use function preg_match; |
127 | 128 | use function preg_match_all; |
128 | 129 | use function spl_object_id; |
@@ -5877,25 +5878,56 @@ public function getPhpVersion(): PhpVersions |
5877 | 5878 | { |
5878 | 5879 | $constType = $this->getGlobalConstantType(new Name('PHP_VERSION_ID')); |
5879 | 5880 | if ($constType !== null && !$this->isOverallPhpVersionRange($constType)) { |
| 5881 | + if ( |
| 5882 | + $constType instanceof IntegerRangeType |
| 5883 | + && $constType->getMin() === ConstantResolver::PHP_MIN_ANALYZABLE_VERSION_ID |
| 5884 | + && $constType->getMax() !== null |
| 5885 | + && $this->getConfiguredPhpVersionRange() === null |
| 5886 | + ) { |
| 5887 | + // A guard like `PHP_VERSION_ID < 80400` only gives an upper bound. Without |
| 5888 | + // a configured version range, the lower bound is merely the lowest version |
| 5889 | + // PHPStan knows, while outside the guard the single analysed PHP version |
| 5890 | + // applies. Keep the lower bound at that version, or as close to it as |
| 5891 | + // the guard allows. |
| 5892 | + $maxVersionId = $constType->getMax(); |
| 5893 | + return new PhpVersions(IntegerRangeType::fromInterval( |
| 5894 | + min($this->services->phpVersion->getVersionId(), $maxVersionId), |
| 5895 | + $maxVersionId, |
| 5896 | + )); |
| 5897 | + } |
| 5898 | + |
5880 | 5899 | return new PhpVersions($constType); |
5881 | 5900 | } |
5882 | 5901 |
|
5883 | | - // The analysed PHP version range comes either from the NEON phpVersion min/max |
5884 | | - // config or from the composer.json "require.php" constraint - the very same |
5885 | | - // source ConstantResolver narrows PHP_VERSION_ID with, so that |
5886 | | - // Scope::getPhpVersion() never contradicts the PHP_VERSION_ID constant. |
| 5902 | + $configuredRange = $this->getConfiguredPhpVersionRange(); |
| 5903 | + if ($configuredRange !== null) { |
| 5904 | + return new PhpVersions($configuredRange); |
| 5905 | + } |
| 5906 | + |
| 5907 | + return new PhpVersions(new ConstantIntegerType($this->services->phpVersion->getVersionId())); |
| 5908 | + } |
| 5909 | + |
| 5910 | + /** |
| 5911 | + * The analysed PHP version range comes either from the NEON phpVersion min/max |
| 5912 | + * config or from the composer.json "require.php" constraint - the very same |
| 5913 | + * source ConstantResolver narrows PHP_VERSION_ID with, so that |
| 5914 | + * Scope::getPhpVersion() never contradicts the PHP_VERSION_ID constant. |
| 5915 | + * Null when neither is set and a single PHP version is analysed. |
| 5916 | + */ |
| 5917 | + private function getConfiguredPhpVersionRange(): ?Type |
| 5918 | + { |
5887 | 5919 | [$minPhpVersion, $maxPhpVersion] = $this->services->configuredPhpVersionRangeHelper->getVersionRange(); |
5888 | 5920 | if ( |
5889 | | - $minPhpVersion !== null |
5890 | | - || ($maxPhpVersion !== null && $maxPhpVersion->getVersionId() !== PhpVersionFactory::MAX_PHP_VERSION) |
| 5921 | + $minPhpVersion === null |
| 5922 | + && ($maxPhpVersion === null || $maxPhpVersion->getVersionId() === PhpVersionFactory::MAX_PHP_VERSION) |
5891 | 5923 | ) { |
5892 | | - return new PhpVersions(IntegerRangeType::fromInterval( |
5893 | | - $minPhpVersion !== null ? $minPhpVersion->getVersionId() : ConstantResolver::PHP_MIN_ANALYZABLE_VERSION_ID, |
5894 | | - $maxPhpVersion !== null ? $maxPhpVersion->getVersionId() : null, |
5895 | | - )); |
| 5924 | + return null; |
5896 | 5925 | } |
5897 | 5926 |
|
5898 | | - return new PhpVersions(new ConstantIntegerType($this->services->phpVersion->getVersionId())); |
| 5927 | + return IntegerRangeType::fromInterval( |
| 5928 | + $minPhpVersion !== null ? $minPhpVersion->getVersionId() : ConstantResolver::PHP_MIN_ANALYZABLE_VERSION_ID, |
| 5929 | + $maxPhpVersion !== null ? $maxPhpVersion->getVersionId() : null, |
| 5930 | + ); |
5899 | 5931 | } |
5900 | 5932 |
|
5901 | 5933 | /** |
|
0 commit comments