Skip to content

Tell the user when a phar runs without the Turbo extension - #6719

Merged
ondrejmirtes merged 3 commits into
phpstan:2.3.xfrom
SanderMuller:turbo-missing-notice
Oct 9, 2026
Merged

ondrejmirtes merged 3 commits into
phpstan:2.3.xfrom
SanderMuller:turbo-missing-notice

Conversation

@SanderMuller

@SanderMuller SanderMuller commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

When phpstan.phar runs without the turbo-ext/ directory next to it, PHPStan Turbo does not load. Nothing tells the user. This happens when a tool downloads only the phar from the release, for example TomasVotruba/need-for-speed#9 and shivammathur/setup-php#1132.

analyse now prints a note right after the existing note about an incompatible extension version:

 ! [NOTE] PHPStan runs without PHPStan Turbo.
 !        With PHPStan Turbo, analysis is up to 60% faster.
 !        Install PHPStan with Composer: composer require --dev phpstan/phpstan
 !        Or install PHPStan Turbo with PIE: pie install phpstan/turbo:2.3.1

The note appears only when all of these are true:

  • PHPStan runs from a phar.
  • PHP is 8.3 or newer, and not a debug build.
  • The platform is one that Turbo ships binaries for.
  • No extension is loaded, for example from a php.ini.
  • There is no turbo-ext/ directory next to the phar.

So a Composer install never shows it, even on a PHP version without a binary yet, and neither does a run from source. On a host without pcntl, the workers still get the extension, and the directory exists, so the note does not show there either. The PIE command includes the PHPStan version, because the extension version must match. A dev build gets plain phpstan/turbo. The runtime checks are shared with findExtension(), so the note and the extension lookup agree on which runtimes can have a binary.

The new turbo-missing-note job in phar.yml runs the built phar twice on PHP 8.4. Alone, it must print the note. With a turbo-ext/ directory next to it, it must not. compiler-tests runs the phar on PHP 8.2, below the minimum, so it cannot cover this. The job's script fails against the 2.3.1 phar, which has no note.

I also built a phar from this branch and ran analyse with it:

  • A copy of the phar alone, on PHP 8.5: the note appears.
  • The same phar with the turbo-ext/ of 2.3.1 next to it: no note, and diagnose says "Turbo extension: enabled".
  • The phar alone on PHP 8.1: no note.
  • The phar alone, with the extension loaded from an ini file in the scan directory, as PIE does: no note. diagnose says "Turbo extension: enabled".

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

One thing I found on the way, not changed here. An extension loaded with php -d extension=... does not survive the OPcache restart in TurboProcessRestarter. The restart passes on only the main php.ini, memory_limit and its own flags. On 2.3.1, php -d extension=<turbo> phpstan.phar diagnose reports "not loaded".

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* it, on a runtime the extension is built for, and no php.ini loads the
* extension either.
*/
public static function isMissingNextToPhar(): bool

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should only error for php-runtime-versions which are compatible with turbo

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm should it share most logic with findExtension?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 5a24d48: both methods now share one helper. The note only shows where findExtension() would look for a binary. That means PHP 8.3 or newer, not a debug build, a phar, and a platform with binaries.

There is no upper bound yet, in either method. A bare phar on a future PHP 8.7 would show the note before an 8.7 binary exists. Should I add one?

Comment thread src/Command/AnalyseCommand.php Outdated
$phpstanVersion = ComposerHelper::getPhpStanVersion();
$errorOutput->getStyle()->note(sprintf(
'PHPStan runs without its Turbo extension.' . "\n"
. 'With the extension, PHPStan is up to 60%% faster.' . "\n"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should mention the "60%" here, as this number will likely change in the future again

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ondřej asked for the number when he suggested this note, so I kept it. I'll drop it if he prefers.

Comment thread src/Command/AnalyseCommand.php Outdated
'PHPStan runs without its Turbo extension.' . "\n"
. 'With the extension, PHPStan is up to 60%% faster.' . "\n"
. 'Install PHPStan with Composer: composer require --dev phpstan/phpstan' . "\n"
. 'Or install the extension with PIE: pie install %s',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

at best mention the full "pie install" command for easy copy/paste

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It prints the full command already. A release includes the version, for example pie install phpstan/turbo:2.3.1, so it can be copied as is. Only a dev build gets plain phpstan/turbo, because a version like 2.3.x-dev@df607f6 is not a phpstan/turbo release.

Comment thread src/Command/AnalyseCommand.php Outdated
} elseif (TurboExtensionSelector::isMissingNextToPhar()) {
$phpstanVersion = ComposerHelper::getPhpStanVersion();
$errorOutput->getStyle()->note(sprintf(
'PHPStan runs without its Turbo extension.' . "\n"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would try to name it "PHPStan Turbo" which feels to me like the proper product-name

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 827a912: all four lines say PHPStan Turbo now.

@staabm

staabm commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

needs e2e test

SanderMuller and others added 2 commits October 9, 2026 14:26
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@SanderMuller

Copy link
Copy Markdown
Contributor Author

Added in 827a912: the turbo-missing-note job in phar.yml runs the built phar on PHP 8.4. It runs it once alone and once with a turbo-ext/ directory next to it. Compiler Tests runs the phar on PHP 8.2, where the note never shows. I ran the job's script against the 2.3.1 phar too, and it fails there.

# the compiler-tests job runs the phar on PHP 8.2, where no binary exists
# and the note is not printed
- name: "Install PHP"
uses: "shivammathur/setup-php@eb7c497e18156a6bbabfef1d3a82760b9eda3962" # 2.40.0

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the same shivammathur/setup-php action, pinned to the same commit, that phar.yml already uses in 13 other steps. The new job needs PHP 8.3 or newer, so it installs PHP the same way as the other jobs.

@ondrejmirtes

Copy link
Copy Markdown
Member

Thank you!

@ondrejmirtes
ondrejmirtes merged commit 184d34e into phpstan:2.3.x Oct 9, 2026
573 of 576 checks passed
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.

4 participants