symfony/finder
Symfony Finder is a fluent API for locating files and directories. Filter by name, size, date, depth, permissions, and content; include/exclude paths; sort results; and iterate efficiently across local filesystems.
Installation:
composer require symfony/finder
No configuration required—ready to use immediately.
First Use Case: Find all PHP files in a directory and its subdirectories:
use Symfony\Component\Finder\Finder;
$finder = Finder::create()
->files()
->in(__DIR__ . '/src')
->name('*.php');
foreach ($finder as $file) {
echo $file->getPathname() . "\n";
}
Where to Look First:
Storage facade).// Find all files in a directory (non-recursive)
$finder = Finder::create()
->files()
->in(public_path('uploads'));
// Find all directories
$finder = Finder::create()
->directories()
->in(storage_path('logs'));
Use chained methods to narrow results:
$finder = Finder::create()
->files()
->in(app_path())
->name('*.php') // Match extension
->notName('*.test.php') // Exclude test files
->size('>10M') // Larger than 10MB
->date('modified', '>1 year ago') // Modified in last year
->mimeType('text/plain'); // Only text files
$finder = Finder::create()
->files()
->sortByModifiedTime() // Newest first
->sortByName() // Alphabetical
->sortByType(); // Directories first
$finder = Finder::create()
->files()
->in(base_path())
->exclude([
'vendor',
'node_modules',
'storage/framework/cache',
]);
Combine multiple search criteria:
$finder = Finder::create()
->files()
->in([storage_path('app'), storage_path('framework')]);
$finder->append(
Finder::create()
->files()
->name('*.log')
->in(log_path())
);
Process files without loading all into memory:
$iterator = Finder::create()
->files()
->in(public_path('assets'))
->getIterator();
foreach ($iterator as $file) {
// Process one file at a time
}
Use Finder with Laravel’s Storage for cloud-based file systems:
use Illuminate\Support\Facades\Storage;
use Symfony\Component\Finder\Finder;
$finder = Finder::create()
->files()
->in(Storage::disk('s3')->path('uploads'));
foreach ($finder as $file) {
$url = Storage::disk('s3')->url($file->getRelativePathname());
}
Build CLI tools for file operations:
use Illuminate\Console\Command;
use Symfony\Component\Finder\Finder;
class OptimizeImages extends Command
{
protected $signature = 'images:optimize';
protected $description = 'Optimize large images';
public function handle()
{
$finder = Finder::create()
->files()
->in(public_path('images'))
->size('>5MB');
foreach ($finder as $file) {
$this->info("Optimizing: {$file->getRelativePathname()}");
// Add optimization logic
}
}
}
Trigger actions when files match criteria:
use Illuminate\Filesystem\Events\FileCreated;
use Symfony\Component\Finder\Finder;
public function handle(FileCreated $event)
{
$finder = Finder::create()
->files()
->in($event->path)
->name('*.log');
if ($finder->count() > 10) {
// Log rotation or cleanup
}
}
Publish only changed files during php artisan vendor:publish:
$finder = Finder::create()
->files()
->in(resource_path('views'))
->notPath('vendor/*')
->ignoreDotFiles(true);
foreach ($finder as $file) {
$this->files->put(
public_path($file->getRelativePathname()),
$file->getContents()
);
}
Mock file systems in tests:
use Symfony\Component\Finder\Finder;
public function testFileDiscovery()
{
$finder = Finder::create()
->files()
->in(__DIR__ . '/tests/files');
$this->assertCount(3, $finder);
}
Avoid Loading All Files at Once:
Use iterators or limit() for large directories:
$finder = Finder::create()
->files()
->in(storage_path('app'))
->limit(100); // Process only 100 files
Combine Filters Early:
Apply restrictive filters (e.g., name(), extension()) before broader ones (e.g., size()) to reduce the search space.
Use ignore() for Common Exclusions:
$finder = Finder::create()
->files()
->in(base_path())
->ignore([
'vendor',
'.git',
'node_modules',
]);
Cache Results for Repeated Use:
Store Finder instances or results in memory/cache if reused frequently:
$cacheKey = 'recent_files';
$finder = cache()->remember($cacheKey, now()->addHour(), function () {
return Finder::create()
->files()
->in(storage_path('logs'))
->date('modified', '>1 day ago');
});
Path Handling Across OSes:
Finder uses forward slashes (/) internally, but paths passed to in() or ignore() must match the OS’s format.str() helpers or realpath() to normalize paths:
$finder = Finder::create()
->files()
->in(str_replace('\\', '/', base_path('src')));
Case Sensitivity in Filenames:
name('*.php') may miss *.PHP files.name('*.php') with Finder::create()->ignoreCase(true) or normalize case:
$finder = Finder::create()
->files()
->in(__DIR__)
->name('*.php')
->ignoreCase(true);
Symlink Traversal:
Finder follows symlinks by default, which may cause infinite loops or unintended directory traversal.$finder = Finder::create()
->files()
->in(__DIR__)
->followLinks(false);
Empty Results from append():
Finder instance can break iteration (fixed in v8.0.4+).Finder instances are non-empty or use hasResults() to check:
$finder = Finder::create()->files()->in('nonexistent');
if ($finder->hasResults()) {
$mainFinder->append($finder);
}
Glob Pattern Quirks:
*test*.php) may not work as expected due to regex conversion.$finder = Finder::create()
->files()
->name('/^test.*\.php$/'); // Regex mode
Memory Leaks with Large Directories:
How can I help you explore Laravel packages today?