Filesystem Component
Symfony 8.0: Компоненты Filesystem и Finder явно указаны в темах экзамена.
Filesystem предоставляет кроссплатформенные операции с файловой системой. Все методы выбрасывают IOException при ошибке.
<?php
declare(strict_types=1);
namespace App\Service;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Filesystem\Exception\IOException;
final class FileManager
{
private readonly Filesystem $filesystem;
public function __construct()
{
$this->filesystem = new Filesystem();
}
public function createProjectStructure(string $baseDir): void
{
// Create directory (recursive by default)
$this->filesystem->mkdir([
"$baseDir/src",
"$baseDir/config",
"$baseDir/tests",
"$baseDir/public",
]);
// Create file with content
$this->filesystem->dumpFile(
"$baseDir/README.md",
"# My Project\n\nDescription here.",
);
// Append to file
$this->filesystem->appendToFile(
"$baseDir/README.md",
"\n\n## Installation\n\nTODO",
);
}
public function copyAssets(string $source, string $target): void
{
// Copy file
$this->filesystem->copy(
"$source/logo.png",
"$target/logo.png",
overwriteNewerFiles: true,
);
// Mirror directory (copy entire directory tree)
$this->filesystem->mirror(
"$source/assets",
"$target/public/assets",
);
}
public function cleanup(string $dir): void
{
// Check existence
if (!$this->filesystem->exists($dir)) {
return;
}
// Remove files and directories
$this->filesystem->remove([
"$dir/cache",
"$dir/logs",
"$dir/temp.txt",
]);
}
}
Основные методы Filesystem
| Метод | Описание |
|---|---|
mkdir($dirs) |
Создать директории |
exists($files) |
Проверить существование |
copy($source, $target) |
Копировать файл |
mirror($source, $target) |
Зеркалировать директорию |
remove($files) |
Удалить файлы/директории |
rename($source, $target) |
Переименовать/переместить |
symlink($source, $target) |
Создать символическую ссылку |
dumpFile($file, $content) |
Создать/перезаписать файл |
appendToFile($file, $content) |
Дописать в файл |
chmod($files, $mode) |
Изменить права |
chown($files, $user) |
Изменить владельца |
chgrp($files, $group) |
Изменить группу |
touch($files) |
Обновить время модификации |
tempnam($dir, $prefix) |
Создать временный файл |
Работа с путями
<?php
declare(strict_types=1);
use Symfony\Component\Filesystem\Path;
// Canonicalize path
$path = Path::canonicalize('/var/www/../log/app.log');
// Result: /var/log/app.log
// Make path relative
$relative = Path::makeRelative(
'/var/www/project/public/index.php',
'/var/www/project',
);
// Result: public/index.php
// Make path absolute
$absolute = Path::makeAbsolute('config/routes.yaml', '/var/www/project');
// Result: /var/www/project/config/routes.yaml
// Join paths
$joined = Path::join('/var/www', 'project', 'public');
// Result: /var/www/project/public
// Get extension
$ext = Path::getExtension('/path/to/file.txt');
// Result: txt
// Check if absolute
$isAbsolute = Path::isAbsolute('/var/www'); // true
$isAbsolute = Path::isAbsolute('var/www'); // false
Finder Component
Finder -- мощный инструмент для поиска файлов и директорий с fluent-интерфейсом.
<?php
declare(strict_types=1);
namespace App\Service;
use Symfony\Component\Finder\Finder;
final class CodeAnalyzer
{
public function findPhpFiles(string $directory): Finder
{
$finder = new Finder();
$finder
->files() // Only files (not directories)
->in($directory) // Search directory
->name('*.php') // File name pattern
->notName('*Test.php')// Exclude pattern
->exclude('vendor') // Exclude directory
->sortByName(); // Sort results
return $finder;
}
public function countLines(string $directory): int
{
$finder = $this->findPhpFiles($directory);
$totalLines = 0;
foreach ($finder as $file) {
// $file is SplFileInfo
$totalLines += substr_count($file->getContents(), "\n");
}
return $totalLines;
}
}
Фильтры поиска
<?php
declare(strict_types=1);
use Symfony\Component\Finder\Finder;
$finder = new Finder();
// Search in multiple directories
$finder->in(['/var/www/project/src', '/var/www/project/lib']);
// Files only or directories only
$finder->files(); // Only files
$finder->directories(); // Only directories
// Name patterns (glob or regex)
$finder->name('*.php'); // Glob
$finder->name('/\.php$/'); // Regex
$finder->name(['*.php', '*.twig']); // Multiple patterns
$finder->notName('*.bak'); // Exclude
// Path filtering
$finder->path('Controller'); // Contains 'Controller' in path
$finder->notPath('vendor'); // Exclude path
// Size filtering
$finder->size('> 1K'); // Greater than 1KB
$finder->size('< 100M'); // Less than 100MB
$finder->size('>= 1K')->size('<= 2M'); // Range
// Date filtering
$finder->date('since yesterday');
$finder->date('> 2025-01-01');
$finder->date('until 2 days ago');
// Depth filtering
$finder->depth('== 0'); // Only current directory
$finder->depth('< 3'); // Max 3 levels deep
$finder->depth('>= 1'); // Skip current directory
// Content filtering
$finder->contains('use Doctrine'); // File contains text
$finder->notContains('deprecated'); // File doesn't contain
// Exclude directories
$finder->exclude(['vendor', 'node_modules', '.git']);
$finder->ignoreDotFiles(true); // Ignore .* files
$finder->ignoreVCS(true); // Ignore VCS files (.git, .svn)
// Symlinks
$finder->followLinks(); // Follow symbolic links
Сортировка
<?php
declare(strict_types=1);
use Symfony\Component\Finder\Finder;
$finder = new Finder();
$finder->files()->in('/path/to/dir');
// Built-in sorts
$finder->sortByName(); // Alphabetical
$finder->sortByModifiedTime(); // Newest last
$finder->sortByAccessedTime(); // By access time
$finder->sortByType(); // Directories first, then files
// Custom sort
$finder->sort(function (\SplFileInfo $a, \SplFileInfo $b): int {
return $b->getSize() <=> $a->getSize(); // Largest first
});
// Reverse sort
$finder->sortByName()->reverseSorting();
SplFileInfo методы
<?php
declare(strict_types=1);
use Symfony\Component\Finder\Finder;
$finder = new Finder();
$finder->files()->in('/path')->name('*.php');
foreach ($finder as $file) {
$file->getFilename(); // "MyClass.php"
$file->getExtension(); // "php"
$file->getBasename('.php'); // "MyClass"
$file->getRelativePath(); // Relative dir from search root
$file->getRelativePathname();// Relative path with filename
$file->getRealPath(); // Absolute path
$file->getPath(); // Directory path
$file->getSize(); // File size in bytes
$file->getMTime(); // Modification time
$file->getContents(); // File contents as string
$file->isReadable(); // Is readable
$file->isWritable(); // Is writable
}
Практический пример: очистка логов
<?php
declare(strict_types=1);
namespace App\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
#[AsCommand(name: 'app:cleanup-logs')]
final class CleanupLogsCommand extends Command
{
public function __construct(
private readonly string $logsDir,
) {
parent::__construct();
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$filesystem = new Filesystem();
$finder = new Finder();
$finder
->files()
->in($this->logsDir)
->name('*.log')
->date('< 7 days ago')
->sortByModifiedTime();
$count = $finder->count();
if ($count === 0) {
$io->success('No old log files to clean up');
return Command::SUCCESS;
}
$totalSize = 0;
foreach ($finder as $file) {
$totalSize += $file->getSize();
$filesystem->remove($file->getRealPath());
}
$io->success(sprintf(
'Removed %d log files (%.2f MB)',
$count,
$totalSize / 1024 / 1024,
));
return Command::SUCCESS;
}
}
Итоги
- Filesystem: кроссплатформенные файловые операции с обработкой ошибок
dumpFile(),copy(),mirror(),remove()-- основные методыPath-- утилиты для работы с путями (canonicalize, join, makeRelative)- Finder: fluent-поиск файлов с фильтрами по имени, размеру, дате, содержимому
$finder->files()->in()->name()->size()->date()-- цепочка фильтровSplFileInfo-- информация о найденном файле