symfony/finder
Symfony Finder provides a fluent API to locate files and directories. Filter by name, path, size, dates, contents, and more; traverse recursively and iterate results easily—ideal for CLI tools, installers, and build scripts.
Installation:
composer require symfony/finder
No additional configuration is required—it’s a standalone component.
First Use Case: Locate 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->getRealPath() . "\n";
}
Where to Look First:
// Find all files in a directory (non-recursive)
$finder = Finder::create()
->files()
->in('/path/to/dir');
// Recursive search with glob patterns
$finder = Finder::create()
->files()
->in('/path/to/dir')
->name('*.{php,js}');
// Files modified in the last 7 days
$finder = Finder::create()
->files()
->in('/logs')
->date('>1 week ago');
// Files larger than 1MB
$finder = Finder::create()
->files()
->in('/uploads')
->size('>1M');
// Exclude 'vendor' and 'node_modules'
$finder = Finder::create()
->files()
->in(__DIR__)
->exclude([
'vendor',
'node_modules',
'*.min.js'
]);
// Sort by modification time (newest first)
$finder = Finder::create()
->files()
->in('/assets')
->sortByModifiedTime('DESC');
// Use with Laravel's Storage facade (for local files)
use Illuminate\Support\Facades\Storage;
$finder = Finder::create()
->files()
->in(storage_path('app/public'))
->name('*.jpg');
foreach ($finder as $file) {
$url = Storage::url($file->getRelativePathname());
// Process URL...
}
// Process files in chunks (memory-efficient for large directories)
$finder = Finder::create()->files()->in('/large/dir');
foreach ($finder as $file) {
// Process $file (e.g., resize images, parse logs)
}
// Get an array of paths (for batch operations)
$paths = iterator_to_array($finder, false);
use Symfony\Component\Finder\Finder;
use Illuminate\Console\Command;
class OptimizeImagesCommand extends Command
{
protected $signature = 'images:optimize';
protected $description = 'Optimize all images in the uploads directory';
public function handle()
{
$finder = Finder::create()
->files()
->in(public_path('uploads'))
->name('*.{jpg,png}');
foreach ($finder as $file) {
$this->info("Optimizing: {$file->getRelativePathname()}");
// Use Intervention Image or similar library
}
}
}
// Register a custom Finder service
public function register()
{
$this->app->singleton('finder', function () {
return Finder::create()
->ignoreDotFiles(false) // Include hidden files
->ignoreUnreadableDirs(true); // Skip permission-denied dirs
});
}
// Trigger actions when files match criteria
$finder = Finder::create()
->files()
->in(storage_path('logs'))
->date('>1 month ago');
foreach ($finder as $file) {
event(new LogFileFound($file));
}
// Mock Finder in unit tests
$finder = $this->createMock(Finder::class);
$finder->method('getIterator')->willReturn(new ArrayIterator([
new SplFileInfo('/fake/path/file1.txt'),
new SplFileInfo('/fake/path/file2.txt'),
]));
Path Separators:
DIRECTORY_SEPARATOR or realpath() for cross-platform compatibility:
$finder->in(__DIR__ . DIRECTORY_SEPARATOR . 'src');
Hidden Files/Directories:
.). Explicitly include them if needed:
$finder->ignoreDotFiles(false);
Performance with Large Directories:
foreach ($finder as $file) { ... } // Better than $finder->getIterator()->toArray()
Symlinks:
$finder->followLinks(false);
Case Sensitivity:
$finder->name('/\.php$/i'); // Case-insensitive regex
Empty Results:
Finder::append() can fail silently if iterators are empty. Validate inputs:
$finder = Finder::create()->files()->in('/nonexistent');
if ($finder->count() === 0) {
$this->error('No files found!');
}
Inspect the Iterator:
$files = iterator_to_array($finder, false);
dd($files);
Check Paths:
getRealPath() to verify absolute paths:
$file->getRealPath(); // Resolves symlinks and relative paths
Date Comparisons:
now() or DateTime for dynamic comparisons:
$finder->date('>' . now()->subDays(7)->format('Y-m-d'));
Size Units:
B, K, M, G for sizes (e.g., >1M for 1MB). Avoid raw bytes unless necessary.Custom Comparators:
Symfony\Component\Finder\Comparator\ComparatorInterface for custom logic (e.g., MIME-type filtering).Event Dispatching:
FileFound, SearchComplete):
class EventfulFinder
{
public function find()
{
$finder = Finder::create()->files()->in($this->path);
foreach ($finder as $file) {
event(new FileFound($file));
}
}
}
Laravel Facade:
// app/Facades/Finder.php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class Finder extends Facade { protected static function getFacadeAccessor() { return 'finder'; } }
Register in AppServiceProvider:
$this->app->bind('finder', function () {
return Finder::create()->ignoreDotFiles(false);
});
Caching Results:
$files = Cache::remember('finder_results', now()->addHours(1), function () {
return iterator_to_array(Finder::create()->files()->in('/data'));
});
vendor, .git) in recursive searches.->limit($n) to cap results:
$finder->limit(1000); // Process only the first 1000 files
How can I help you explore Laravel packages today?