Skip to content

Commit 7aa3326

Browse files
authored
[perf] Cache realpath() of skip patterns in FileInfoMatcher (#8699)
1 parent 07cfb5a commit 7aa3326

2 files changed

Lines changed: 24 additions & 1 deletion

File tree

‎src/Skipper/Matcher/FileInfoMatcher.php‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@
1111
*/
1212
final class FileInfoMatcher
1313
{
14+
/**
15+
* PHP does not cache a failed realpath() lookup, and a wildcard pattern fails it for every file
16+
*
17+
* @var array<string, string|false>
18+
*/
19+
private array $realpathByPattern = [];
20+
1421
/**
1522
* Returns the original (un-normalized) pattern that matched, so callers can report the exact
1623
* configured path. Returns null when no pattern matches.
@@ -90,7 +97,7 @@ private function matchFnmatch(string $matchingPath, string $filePath): bool
9097

9198
private function matchRealpath(string $matchingPath, string $filePath): bool
9299
{
93-
$realPathMatchingPath = realpath($matchingPath);
100+
$realPathMatchingPath = $this->realpathByPattern[$matchingPath] ??= realpath($matchingPath);
94101
if ($realPathMatchingPath === false) {
95102
return false;
96103
}

‎tests/Skipper/Matcher/FileInfoMatcherTest.php‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,22 @@ public function testMatchPatternReturnsNullWhenNoPatternMatches(): void
3535
$this->assertNull($matchedPattern);
3636
}
3737

38+
public function testRealPathOfEachPatternIsResolvedSeparatelyOnRepeatedCalls(): void
39+
{
40+
// the file paths are not real paths, so only the realpath() comparison can match them
41+
$pathInPattern = __DIR__ . '/Fixture/path/in';
42+
$inPattern = __DIR__ . '/Fixture/in';
43+
$patterns = [$pathInPattern, $inPattern];
44+
45+
$pathInFile = __DIR__ . '/Fixture/path/with/../in/it/KeepThisFile.txt';
46+
$inFile = __DIR__ . '/Fixture/path/../in/it/KeepThisFile.txt';
47+
48+
for ($i = 0; $i < 2; ++$i) {
49+
$this->assertSame($pathInPattern, $this->fileInfoMatcher->matchPattern($pathInFile, $patterns));
50+
$this->assertSame($inPattern, $this->fileInfoMatcher->matchPattern($inFile, $patterns));
51+
}
52+
}
53+
3854
#[DataProvider('providePatterns')]
3955
public function testPatternNormalization(string $filePath, string $filePattern, bool $shouldMatch): void
4056
{

0 commit comments

Comments
 (0)