| Subject |
Details |
| Rector version |
2.6.6 |
| Installed as |
composer dependency |
ChangedFilesDetector keys every cache entry on the absolute path of the file:
private function getFilePathCacheKey(string $filePath): string
{
return $this->fileHasher->hash($this->resolvePath($filePath) . $this->scopeSuffix);
}
private function resolvePath(string $filePath): string
{
$realPath = realpath($filePath);
// ...
return $realPath;
}
The path is hashed into the cache file's name, so the cache is bound to one location on disk. Move the project - a second git worktree, a CI checkout, a container mount - and the cache is 100% misses while containing nothing that could be rewritten to fix it.
Measurements
A 12 762-file project, 14 cores, PHP 8.5.10.
| Scenario |
Wall time |
| fresh checkout, empty cache |
224 s |
| same checkout, warm cache |
5 s |
| fresh checkout, cache copied from another checkout of the same commit |
247 s (291 MB copied for nothing) |
For comparison, the same experiment with the other two tools in the same toolchain, copying their caches into the same fresh checkout:
| Tool |
cold |
seeded from another checkout |
| Pint (PHP-CS-Fixer) |
105 s |
2.7 s |
| PHPStan |
43 s |
4.4 s |
| Rector |
224 s |
247 s |
Rector's cache records nothing about the environment. Grepping all 12 761 entries of a populated tmp/rector finds zero references to a PHP version, an extension list or an OS - each entry is just a content hash. The absolute path is the only thing standing between that cache and reuse somewhere else.
Proposal
Key on the path relative to the project root and re-absolutize on read, as PHPStan does.
Two honest caveats:
- Existing caches invalidate once on upgrade.
- Files outside the project root (if any can reach the detector) need a defined behaviour - PHPStan's transformer leaves an already-absolute path untouched, which also keeps old-format caches readable.
I am happy to send a PR if you agree with the direction. I would rather hear which shape you want (anchor directory as a constructor dependency vs resolving it from the config) than guess and have it rewritten.
ChangedFilesDetectorkeys every cache entry on the absolute path of the file:The path is hashed into the cache file's name, so the cache is bound to one location on disk. Move the project - a second git worktree, a CI checkout, a container mount - and the cache is 100% misses while containing nothing that could be rewritten to fix it.
Measurements
A 12 762-file project, 14 cores, PHP 8.5.10.
For comparison, the same experiment with the other two tools in the same toolchain, copying their caches into the same fresh checkout:
Rector's cache records nothing about the environment. Grepping all 12 761 entries of a populated
tmp/rectorfinds zero references to a PHP version, an extension list or an OS - each entry is just a content hash. The absolute path is the only thing standing between that cache and reuse somewhere else.Proposal
Key on the path relative to the project root and re-absolutize on read, as PHPStan does.
Two honest caveats:
I am happy to send a PR if you agree with the direction. I would rather hear which shape you want (anchor directory as a constructor dependency vs resolving it from the config) than guess and have it rewritten.