diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index 9d4f275e4..61f8d7679 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -568,8 +568,6 @@
$const_name
- $type[0]
- $type[0][0]
diff --git a/src/Psalm/Config.php b/src/Psalm/Config.php
index cca108354..4ed538975 100644
--- a/src/Psalm/Config.php
+++ b/src/Psalm/Config.php
@@ -2238,6 +2238,10 @@ class Config
$stubsDir . 'SPL.phpstub',
];
+ if ($codebase->analysis_php_version_id >= 7_04_00) {
+ $this->internal_stubs[] = $stubsDir . 'Php74.phpstub';
+ }
+
if ($codebase->analysis_php_version_id >= 8_00_00) {
$this->internal_stubs[] = $stubsDir . 'CoreGenericAttributes.phpstub';
$this->internal_stubs[] = $stubsDir . 'Php80.phpstub';
diff --git a/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php b/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php
index a418a52bc..6be055ea4 100644
--- a/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php
+++ b/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php
@@ -200,6 +200,10 @@ class ProjectAnalyzer
UnnecessaryVarAnnotation::class,
];
+ private const PHP_VERSION_REGEX = '^(0|[1-9]\d*)\.(0|[1-9]\d*)(?:\..*)?$';
+
+ private const PHP_SUPPORTED_VERSIONS_REGEX = '^(5\.[456]|7\.[01234]|8\.[0123])(\..*)?$';
+
/**
* @param array $generated_report_options
*/
@@ -1179,8 +1183,16 @@ class ProjectAnalyzer
*/
public function setPhpVersion(string $version, string $source): void
{
- if (!preg_match('/^(5\.[456]|7\.[01234]|8\.[012])(\..*)?$/', $version)) {
- throw new UnexpectedValueException('Expecting a version number in the format x.y');
+ if (!preg_match('/' . self::PHP_VERSION_REGEX . '/', $version)) {
+ throw new UnexpectedValueException('Expecting a version number in the format x.y or x.y.z');
+ }
+
+ if (!preg_match('/' . self::PHP_SUPPORTED_VERSIONS_REGEX . '/', $version)) {
+ throw new UnexpectedValueException(
+ 'Psalm supports PHP version ">=5.4". The specified version '
+ . $version
+ . " is either not supported or doesn't exist.",
+ );
}
[$php_major_version, $php_minor_version] = explode('.', $version);
diff --git a/src/Psalm/Internal/CliUtils.php b/src/Psalm/Internal/CliUtils.php
index 1e5a1abdd..86f6b3261 100644
--- a/src/Psalm/Internal/CliUtils.php
+++ b/src/Psalm/Internal/CliUtils.php
@@ -12,6 +12,7 @@ use Psalm\Exception\ConfigNotFoundException;
use Psalm\Internal\Analyzer\ProjectAnalyzer;
use Psalm\Report;
use RuntimeException;
+use UnexpectedValueException;
use function array_filter;
use function array_key_exists;
@@ -485,7 +486,15 @@ final class CliUtils
}
if ($version !== null && $source !== null) {
- $project_analyzer->setPhpVersion($version, $source);
+ try {
+ $project_analyzer->setPhpVersion($version, $source);
+ } catch (UnexpectedValueException $e) {
+ fwrite(
+ STDERR,
+ $e->getMessage() . PHP_EOL,
+ );
+ exit(2);
+ }
}
}
diff --git a/src/Psalm/Type/Reconciler.php b/src/Psalm/Type/Reconciler.php
index 76bfb230d..4f93c7979 100644
--- a/src/Psalm/Type/Reconciler.php
+++ b/src/Psalm/Type/Reconciler.php
@@ -423,6 +423,10 @@ class Reconciler
{
foreach ($new_types as $nk => $type) {
if (strpos($nk, '[') || strpos($nk, '->')) {
+ $type = array_values($type);
+ if (!isset($type[0][0])) {
+ continue;
+ }
if ($type[0][0] instanceof IsEqualIsset
|| $type[0][0] instanceof IsIsset
|| $type[0][0] instanceof NonEmpty
diff --git a/stubs/Php74.phpstub b/stubs/Php74.phpstub
new file mode 100644
index 000000000..4ade3a6da
--- /dev/null
+++ b/stubs/Php74.phpstub
@@ -0,0 +1,11 @@
+ return
+ *
+ * @param null|string|array $allowed_tags
+ */
+function strip_tags(string $string, null|string|array $allowed_tags = null) : string {}