diff --git a/bin/phpstan b/bin/phpstan
index 537f3e123d..a8c0fd8dd0 100755
--- a/bin/phpstan
+++ b/bin/phpstan
@@ -3,6 +3,7 @@
use PHPStan\Command\AnalyseCommand;
use PHPStan\Command\ClearResultCacheCommand;
+use PHPStan\Command\DiagnoseCommand;
use PHPStan\Command\DumpParametersCommand;
use PHPStan\Command\FixerWorkerCommand;
use PHPStan\Command\WorkerCommand;
@@ -166,5 +167,6 @@ use Symfony\Component\Console\Helper\ProgressBar;
$application->add(new ClearResultCacheCommand($reversedComposerAutoloaderProjectPaths));
$application->add(new FixerWorkerCommand($reversedComposerAutoloaderProjectPaths));
$application->add(new DumpParametersCommand($reversedComposerAutoloaderProjectPaths));
+ $application->add(new DiagnoseCommand($reversedComposerAutoloaderProjectPaths));
$application->run();
})();
diff --git a/src/Command/DiagnoseCommand.php b/src/Command/DiagnoseCommand.php
new file mode 100644
index 0000000000..608cf732f1
--- /dev/null
+++ b/src/Command/DiagnoseCommand.php
@@ -0,0 +1,104 @@
+setName(self::NAME)
+ ->setDescription('Shows diagnose information about PHPStan and extensions')
+ ->setDefinition([
+ new InputOption('configuration', 'c', InputOption::VALUE_REQUIRED, 'Path to project configuration file'),
+ new InputOption(AnalyseCommand::OPTION_LEVEL, 'l', InputOption::VALUE_REQUIRED, 'Level of rule options - the higher the stricter'),
+ new InputOption('autoload-file', 'a', InputOption::VALUE_REQUIRED, 'Project\'s additional autoload file path'),
+ new InputOption('debug', null, InputOption::VALUE_NONE, 'Show debug information - do not catch internal errors'),
+ new InputOption('memory-limit', null, InputOption::VALUE_REQUIRED, 'Memory limit for clearing result cache'),
+ ]);
+ }
+
+ protected function initialize(InputInterface $input, OutputInterface $output): void
+ {
+ if ((bool) $input->getOption('debug')) {
+ $application = $this->getApplication();
+ if ($application === null) {
+ throw new ShouldNotHappenException();
+ }
+ $application->setCatchExceptions(false);
+ return;
+ }
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int
+ {
+ $memoryLimit = $input->getOption('memory-limit');
+ $autoloadFile = $input->getOption('autoload-file');
+ $configuration = $input->getOption('configuration');
+ $level = $input->getOption(AnalyseCommand::OPTION_LEVEL);
+
+ if (
+ (!is_string($memoryLimit) && $memoryLimit !== null)
+ || (!is_string($autoloadFile) && $autoloadFile !== null)
+ || (!is_string($configuration) && $configuration !== null)
+ || (!is_string($level) && $level !== null)
+ ) {
+ throw new ShouldNotHappenException();
+ }
+
+ try {
+ $inceptionResult = CommandHelper::begin(
+ $input,
+ $output,
+ [],
+ $memoryLimit,
+ $autoloadFile,
+ $this->composerAutoloaderProjectPaths,
+ $configuration,
+ null,
+ $level,
+ false,
+ );
+ } catch (InceptionNotSuccessfulException) {
+ return 1;
+ }
+
+ $container = $inceptionResult->getContainer();
+ $output = $inceptionResult->getStdOutput();
+
+ /** @var PHPStanDiagnoseExtension $phpstanDiagnoseExtension */
+ $phpstanDiagnoseExtension = $container->getService('phpstanDiagnoseExtension');
+
+ // not using tag for this extension to make sure it's always first
+ $phpstanDiagnoseExtension->print($output);
+
+ /** @var DiagnoseExtension $extension */
+ foreach ($container->getServicesByTag(DiagnoseExtension::EXTENSION_TAG) as $extension) {
+ $extension->print($output);
+ }
+
+ return 0;
+ }
+
+}
diff --git a/src/Diagnose/DiagnoseExtension.php b/src/Diagnose/DiagnoseExtension.php
index 5df5d628ef..084134495a 100644
--- a/src/Diagnose/DiagnoseExtension.php
+++ b/src/Diagnose/DiagnoseExtension.php
@@ -26,6 +26,6 @@ interface DiagnoseExtension
public const EXTENSION_TAG = 'phpstan.diagnoseExtension';
- public function print(Output $errorOutput): void;
+ public function print(Output $output): void;
}
diff --git a/src/Diagnose/PHPStanDiagnoseExtension.php b/src/Diagnose/PHPStanDiagnoseExtension.php
index 9184987cb8..a7eb786ed8 100644
--- a/src/Diagnose/PHPStanDiagnoseExtension.php
+++ b/src/Diagnose/PHPStanDiagnoseExtension.php
@@ -15,23 +15,23 @@ public function __construct(private PhpVersion $phpVersion)
{
}
- public function print(Output $errorOutput): void
+ public function print(Output $output): void
{
$phpRuntimeVersion = new PhpVersion(PHP_VERSION_ID);
- $errorOutput->writeLineFormatted(sprintf(
+ $output->writeLineFormatted(sprintf(
'PHP runtime version: %s',
$phpRuntimeVersion->getVersionString(),
));
- $errorOutput->writeLineFormatted(sprintf(
+ $output->writeLineFormatted(sprintf(
'PHP version for analysis: %s (from %s)',
$this->phpVersion->getVersionString(),
$this->phpVersion->getSourceLabel(),
));
- $errorOutput->writeLineFormatted(sprintf(
+ $output->writeLineFormatted(sprintf(
'PHPStan version: %s',
ComposerHelper::getPhpStanVersion(),
));
- $errorOutput->writeLineFormatted('');
+ $output->writeLineFormatted('');
}
}