diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 2d48c37e3c0..5bfed46f51d 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -2028,6 +2028,23 @@ jobs: ../bashunit -a contains 'Foo.php:11:Instantiated class Ds\Vector not found.' "$OUTPUT" ../bashunit -a contains 'Bar.php:15:Call to an undefined method Ds\Pair::copy().' "$OUTPUT" ../bashunit -a not_contains 'Ds\Seq' "$OUTPUT" + - script: | + echo " test.php + XDEBUG_HANDLER_DEBUG=1 bin/phpstan analyse test.php 2>&1 | tee -a output.txt + e2e/bashunit -a file_contains output.txt "Process restarting" + coverage: "pcov" + - script: | + echo " test.php + XDEBUG_HANDLER_DEBUG=1 bin/phpstan analyse test.php 2>&1 | tee -a output.txt + e2e/bashunit -a file_contains output.txt "Process restarting" + coverage: "pcov" + ini-values: "pcov.enabled=1" + - script: | + echo " test.php + XDEBUG_HANDLER_DEBUG=1 bin/phpstan analyse test.php 2>&1 | tee -a output.txt + e2e/bashunit -a file_not_contains output.txt "Process restarting" + coverage: "pcov" + ini-values: "pcov.enabled=0" steps: - name: Harden the runner (Audit all outbound calls) @@ -2041,7 +2058,8 @@ jobs: - name: "Install PHP" uses: "shivammathur/setup-php@eb7c497e18156a6bbabfef1d3a82760b9eda3962" # 2.40.0 with: - coverage: "none" + coverage: ${{ matrix.coverage || 'none' }} + ini-values: ${{ matrix.ini-values || '' }} php-version: "8.2" tools: ${{ matrix.tools }} extensions: ${{ matrix.extensions }} diff --git a/src/Command/CommandHelper.php b/src/Command/CommandHelper.php index 0dfe1c3d191..9cc41d7c62f 100644 --- a/src/Command/CommandHelper.php +++ b/src/Command/CommandHelper.php @@ -3,7 +3,6 @@ namespace PHPStan\Command; use Composer\Semver\Semver; -use Composer\XdebugHandler\XdebugHandler; use Nette\DI\Helpers; use Nette\DI\InvalidConfigurationException; use Nette\DI\ServiceCreationException; @@ -32,6 +31,7 @@ use PHPStan\Internal\DirectoryCreator; use PHPStan\Internal\DirectoryCreatorException; use PHPStan\Process\ForkedChildCrashReporter; +use PHPStan\Process\ProcessRestarter; use PHPStan\ShouldNotHappenException; use ReflectionClass; use Symfony\Component\Console\Input\InputInterface; @@ -104,22 +104,22 @@ public static function begin( $errorOutput = new SymfonyOutput($symfonyErrorOutput, new SymfonyStyle(new ErrorsConsoleStyle($input, $symfonyErrorOutput))); if (!$allowXdebug) { - $xdebug = new XdebugHandler('phpstan'); + $xdebug = new ProcessRestarter('phpstan'); $xdebug->setPersistent(); $xdebug->check(); unset($xdebug); } if ($allowXdebug) { - if (!XdebugHandler::isXdebugActive()) { + if (!ProcessRestarter::isXdebugActive()) { $errorOutput->getStyle()->note('You are running with "--xdebug" enabled, but the Xdebug PHP extension is not active. The process will not halt at breakpoints.'); } else { $errorOutput->getStyle()->note("You are running with \"--xdebug\" enabled, and the Xdebug PHP extension is active.\nThe process will halt at breakpoints, but PHPStan will run much slower.\nUse this only if you are debugging PHPStan itself or your custom extensions."); } - } elseif (XdebugHandler::isXdebugActive()) { + } elseif (ProcessRestarter::isXdebugActive()) { $errorOutput->getStyle()->note('The Xdebug PHP extension is active, but "--xdebug" is not used. This may slow down performance and the process will not halt at breakpoints.'); } elseif ($debugEnabled) { - $v = XdebugHandler::getSkippedVersion(); + $v = ProcessRestarter::getSkippedVersion(); if ($v !== '') { $errorOutput->getStyle()->note( "The Xdebug PHP extension is active, but \"--xdebug\" is not used.\n" . diff --git a/src/Process/ProcessRestarter.php b/src/Process/ProcessRestarter.php new file mode 100644 index 00000000000..ca767701803 --- /dev/null +++ b/src/Process/ProcessRestarter.php @@ -0,0 +1,56 @@ + */ + private array $extensions = []; + + #[Override] + protected function requiresRestart(bool $default): bool + { + // pcov has a perf impact similar to xdebug, so we want to disable it + if (extension_loaded('pcov') && ini_get('pcov.enabled') === '1') { + $this->extensions[] = 'pcov'; + } + + // tideways hooks deep in the php engine, so it can segfault when running phpstan with turbo. + if (extension_loaded('tideways')) { + $this->extensions[] = 'tideways'; + } + + return $default || count($this->extensions) > 0; + } + + #[Override] + protected function restart(array $command): void + { + if (count($this->extensions) > 0) { + $content = file_get_contents((string) $this->tmpIni); + + if ($content !== false) { + foreach ($this->extensions as $extension) { + $regex = '/^\s*((?:zend_)?extension\s*=.*' . $extension . '.*)$/mi'; + $content = preg_replace($regex, ';$1', $content) . PHP_EOL; + } + file_put_contents((string) $this->tmpIni, $content); + } + } + + parent::restart($command); + } + +}