Skip to content

Let another program that loads the phar use PHPStan Turbo - #6720

Open
SanderMuller wants to merge 1 commit into
phpstan:2.3.xfrom
SanderMuller:turbo-host-phar-path
Open

SanderMuller wants to merge 1 commit into
phpstan:2.3.xfrom
SanderMuller:turbo-host-phar-path

Conversation

@SanderMuller

Copy link
Copy Markdown
Contributor

Rector loads PHPStan's phar from vendor/phpstan/phpstan, and it gets a lot faster with PHPStan Turbo. On rector-src with its own rector.php, Rector takes 7.9 s instead of 11.8 s, and 60 s of CPU instead of 98 s. Those are medians of 5 cold runs with 14 workers, on an M4 Pro with PHP 8.5. Rector calls the API below, with a phar built from this branch. The output is the same with and without Turbo.

To get there, Rector needs the same three calls as bin/phpstan. But these calls find the phar through Phar::running(), which is empty when Rector is the script that runs.

This adds an optional ?string $pharPath to TurboProcessRestarter::restartIfSuitable(), TurboExtensionEnabler::trustOwnTypesIfSuitable() and TurboExtensionEnabler::activateIfCompatible(), and to TurboExtensionSelector::findExtension() and findExtensionForWorkers(), which they call. Without the argument, nothing changes. The three methods that another program calls are now @api. A path that is passed in goes through realpath(). Code compiled from the phar carries the resolved path that Composer's bootstrap.php opens it with. Without realpath(), a path like bin/../vendor/... switches trusted types on, but they have no effect. tests/bootstrap.php calls activateIfCompatible(), so its phpstanApi.method ignore is not needed any more.

Rector would call them right after its Composer autoloader:

$phpstanPhar = __DIR__ . '/../vendor/phpstan/phpstan/phpstan.phar';
TurboProcessRestarter::restartIfSuitable($_SERVER['argv'], $phpstanPhar);
TurboExtensionEnabler::trustOwnTypesIfSuitable($_SERVER['argv'], $phpstanPhar);
TurboExtensionEnabler::activateIfCompatible($phpstanPhar);

Its workers start as new processes, so each of them restarts once in the same way. I checked the main process and all 14 workers. In each one the extension is active and OPcache is on. A class-typed parameter check in the phar is dropped, the same as inside PHPStan. With Rector's --debug, the checks stay, like with PHPStan's.

Rector needs two changes of its own. One is merged: rectorphp/rector-src#8564 removes extra arguments to the TypeTraverser callback, which the native callback rejects. The other is still to do: Rector's preload.php must skip PhpParser\NodeTraverser when Turbo has already declared it.

make tests and make phpstan pass, and phpcs reports no errors on the changed files.

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant