Store PhpStorm stub paths in the reflection cache relative to the stubs root - #6179
Merged
Conversation
The first run fills the reflection cache for PHP built-in symbols in
sys_get_temp_dir(); the installation is then moved and PHPStan runs
again with the same cache. The cached blobs store absolute paths to the
PhpStorm stub files while the cache key contains only package versions,
so the second run currently crashes with:
Internal error: ".../phpstorm-stubs/date/date_c.php" is not a file
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…bs root The cache key for PHP built-in reflections deliberately contains no paths, so the entries are shared by every PHPStan installation with the same package versions - but the exported blob recorded the absolute stub file path of the installation that filled the cache. Importing it after that installation was moved or deleted crashed with "... is not a file", and the entries survive clear-result-cache, so there was no way to recover. The stub path is now stored relative to the phpstorm-stubs package root and resolved against the current installation on import, with an is_file() guard that turns any unresolvable path into a plain cache miss. The variable key version bump invalidates existing entries with absolute paths. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ondrejmirtes
force-pushed
the
e2e-moved-phpstan-installation
branch
from
August 4, 2026 21:17
d03d7a9 to
b334e5d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the regression introduced in ae5fd31 (Cache reflections built from the PhpStorm stubs).
The mechanism:
CachedPhpInternalSourceLocatorkeys the cache only by package versions (better-reflection, phpstorm-stubs, target PHP version) — no paths — so the entries are shared by every installation with the same versions, and survive the installation being moved.exportToCache()blob however stored the absolute path of the stub file inside the installation that filled the cache (.../vendor/jetbrains/phpstorm-stubs/...; in the phar case the path embeds the phar's absolute location).InternalLocatedSource::importFromCache()eagerly runsFileChecker::assertReadableFile()+file_get_contents()on that path, so a warm run from a moved installation — or a different installation sharingsys_get_temp_dir() . '/phpstan', like rotating Jenkins workspaces — crashed withInternal error: "..." is not a file. The entries also surviveclear-result-cache, so there was no way to recover.The first commit adds an e2e test: copy the checkout to
/tmp/phpstan-install-1, analyse a small file using built-in symbols (fills the cache), move the installation to/tmp/phpstan-install-2, run the same analysis again. It failed with the internal error above before the fix.The second commit fixes it: the stub path is stored relative to the phpstorm-stubs package root (
phpstorm-stubs:date/date_c.php) and resolved against the current installation on import, so the entries stay shared across installations and moves. Anis_file()guard turns any unresolvable path into a plain cache miss, making this class of crash impossible by construction. The variable-key version bump (v1→v2) invalidates existing poisoned entries with absolute paths, rescuing already-affected caches.Verified locally besides the e2e: a warm in-place run rewrites 0 cache files (the relative entries really are imported), and a second installation at a different path shares the same warm entries. Keeping the cache (rather than reverting it) is backed by benchmarks: it saves ~1.5–3% CPU on runs with a cold result cache (ABBA pairs, paired t-test).
Closes phpstan/phpstan#15023
🤖 Generated with Claude Code