Skip to content

Commit 1872a85

Browse files
committed
fix: validate files in FilesSnapshot before processing
Add check to ensure each file is valid before processing. Without this change filemtime throws an error if the file doesn't exist but is part of cache, which is very common in dev environment. For production it won't matter since is_file is cached, for some reason is_file is also faster than file_exists. Symfony codebase also prefers is_file over file_exists when checking existence of php file.
1 parent 0ef3465 commit 1872a85

File tree

2 files changed

+34
-1
lines changed

2 files changed

+34
-1
lines changed

src/Cache/FilesSnapshot.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use ReflectionClass;
88

99
use function array_unique;
10+
use function is_file;
1011
use function Safe\filemtime;
1112

1213
class FilesSnapshot
@@ -24,6 +25,10 @@ public static function for(array $files): self
2425
$dependencies = [];
2526

2627
foreach (array_unique($files) as $file) {
28+
if (! is_file($file)) {
29+
continue;
30+
}
31+
2732
$dependencies[$file] = filemtime($file);
2833
}
2934

tests/Cache/FilesSnapshotTest.php

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,37 @@ public function testTracksChangesInFile(): void
6969
self::assertTrue($snapshot->changed());
7070
}
7171

72+
public function testIgnoresNonExistentFiles(): void
73+
{
74+
$nonExistentFile = '/path/to/non/existent/file.php';
75+
76+
$snapshot = FilesSnapshot::for([$nonExistentFile]);
77+
78+
self::assertFalse($snapshot->changed());
79+
}
80+
81+
public function testIgnoresNonExistentFilesInMixedList(): void
82+
{
83+
$existingFile = (new \ReflectionClass(FooType::class))->getFileName();
84+
$nonExistentFile1 = '/path/to/non/existent/file1.php';
85+
$nonExistentFile2 = '/path/to/non/existent/file2.php';
86+
87+
$snapshot = FilesSnapshot::for([
88+
$nonExistentFile1,
89+
$existingFile,
90+
$nonExistentFile2,
91+
]);
92+
93+
self::assertFalse($snapshot->changed());
94+
95+
$this->touch($existingFile);
96+
97+
self::assertTrue($snapshot->changed());
98+
}
99+
72100
private function touch(string $fileName): void
73101
{
74102
touch($fileName, filemtime($fileName) + 1);
75103
clearstatcache();
76104
}
77-
}
105+
}

0 commit comments

Comments
 (0)