Finder : recherche de fichiers
Besoin de trouver des fichiers correspondant à un certain masque ? Finder vous y aidera. C'est un outil polyvalent et rapide pour parcourir la structure des répertoires.
Installation :
composer require nette/utils
Les exemples supposent qu'un alias a été créé :
use Nette\Utils\Finder;
Utilisation
Montrons d'abord comment vous pouvez utiliser Nette\Utils\Finder pour lister les noms de fichiers avec les
extensions .txt
et .md
dans le répertoire courant :
foreach (Finder::findFiles(['*.txt', '*.md']) as $name => $file) {
echo $file;
}
Le répertoire par défaut pour la recherche est le répertoire courant, mais vous pouvez le modifier à l'aide des méthodes
in() ou from(). La variable $file
est une instance de la classe FileInfo avec de nombreuses méthodes utiles. La clé $name
contient le chemin du fichier
sous forme de chaîne.
Que rechercher ?
En plus de la méthode findFiles()
, il existe aussi findDirectories()
, qui recherche uniquement les
répertoires, et find()
, qui recherche les deux. Ces méthodes sont statiques, elles peuvent donc être appelées
sans créer d'instance. Le paramètre avec le masque est optionnel, si vous ne le spécifiez pas, tout sera recherché.
foreach (Finder::find() as $file) {
echo $file; // maintenant tous les fichiers et répertoires seront affichés
}
À l'aide des méthodes files()
et directories()
, vous pouvez compléter ce qui doit être
recherché. Les méthodes peuvent être appelées de manière répétée et un tableau de masques peut également être spécifié
comme paramètre :
Finder::findDirectories('vendor') // tous les répertoires
->files(['*.php', '*.phpt']); // plus tous les fichiers PHP
Une alternative aux méthodes statiques est de créer une instance à l'aide de new Finder
(un objet fraîchement
créé de cette manière ne recherche rien) et de spécifier ce qu'il faut rechercher à l'aide de files()
et
directories()
:
(new Finder)
->directories() // tous les répertoires
->files('*.php'); // plus tous les fichiers PHP
Dans le masque, vous pouvez utiliser les caractères génériques *
,
**
, ?
et [...]
. Vous pouvez même spécifier des répertoires, par exemple
src/*.php
recherchera tous les fichiers PHP dans le répertoire src
.
Les liens symboliques sont également considérés comme des répertoires ou des fichiers.
Où rechercher ?
Le répertoire par défaut pour la recherche est le répertoire courant. Vous le modifiez à l'aide des méthodes
in()
et from()
. Comme les noms des méthodes l'indiquent, in()
recherche uniquement dans le
répertoire donné, tandis que from()
recherche également dans ses sous-répertoires (récursivement). Si vous
souhaitez rechercher récursivement dans le répertoire courant, vous pouvez utiliser from('.')
.
Ces méthodes peuvent être appelées plusieurs fois ou recevoir plusieurs chemins sous forme de tableau, les fichiers seront
alors recherchés dans tous les répertoires. Si l'un des répertoires n'existe pas, une exception
Nette\UnexpectedValueException
sera levée.
Finder::findFiles('*.php')
->in(['src', 'tests']) // recherche directement dans src/ et tests/
->from('vendor'); // recherche également dans les sous-répertoires de vendor/
Les chemins relatifs sont relatifs au répertoire courant. Il est bien sûr possible de spécifier également des chemins absolus :
Finder::findFiles('*.php')
->in('/var/www/html');
Il est possible d'utiliser des caractères génériques *
,
**
, ?
dans le chemin. Vous pouvez ainsi, par exemple, à l'aide du chemin src/*/*.php
,
rechercher tous les fichiers PHP dans les répertoires de deuxième niveau du répertoire src
. Le caractère
**
, appelé globstar, est un atout puissant, car il permet de rechercher également dans les sous-répertoires : à
l'aide de src/**/tests/*.php
, vous recherchez tous les fichiers PHP dans le répertoire tests
situé
dans src
ou dans n'importe lequel de ses sous-répertoires.
Inversement, les caractères génériques [...]
ne sont pas supportés dans le chemin, c'est-à-dire qu'ils n'ont
pas de signification spéciale, afin d'éviter un comportement indésirable dans le cas où vous rechercheriez par exemple
in(__DIR__)
et que, par hasard, les caractères []
apparaîtraient dans le chemin.
Lors de la recherche de fichiers et de répertoires en profondeur, le répertoire parent est retourné en premier, puis les
fichiers qu'il contient, ce qui peut être inversé à l'aide de childFirst()
.
Caractères génériques
Dans le masque, vous pouvez utiliser plusieurs caractères spéciaux :
*
– remplace n'importe quel nombre de caractères quelconques (sauf/
)**
– remplace n'importe quel nombre de caractères quelconques y compris/
(c'est-à-dire qu'il est possible de rechercher sur plusieurs niveaux)?
– remplace un caractère quelconque (sauf/
)[a-z]
– remplace un caractère de la liste de caractères entre crochets[!a-z]
– remplace un caractère en dehors de la liste de caractères entre crochets
Exemples d'utilisation :
img/?.png
– fichiers avec un nom d'une seule lettre0.png
,1.png
,x.png
, etc.logs/[0-9][0-9][0-9][0-9]-[01][0-9]-[0-3][0-9].log
– logs au formatYYYY-MM-DD
src/**/tests/*
– fichiers dans les répertoiressrc/tests
,src/foo/tests
,src/foo/bar/tests
et ainsi de suite.docs/**.md
– tous les fichiers avec l'extension.md
dans tous les sous-répertoires du répertoiredocs
Exclusion
À l'aide de la méthode exclude()
, il est possible d'exclure des fichiers et des répertoires de la recherche.
Vous spécifiez un masque auquel le fichier ne doit pas correspondre. Exemple de recherche de fichiers *.txt
sauf
ceux qui contiennent la lettre X
dans leur nom :
Finder::findFiles('*.txt')
->exclude('*X*');
Pour omettre les sous-répertoires parcourus, utilisez exclude()
:
Finder::findFiles('*.php')
->from($dir)
->exclude('temp', '.git')
Filtrage
Finder offre plusieurs méthodes pour filtrer les résultats (c'est-à-dire les réduire). Vous pouvez les combiner et les appeler de manière répétée.
À l'aide de size()
, nous filtrons par taille de fichier. De cette manière, nous trouvons les fichiers dont la
taille est comprise entre 100 et 200 octets :
Finder::findFiles('*.php')
->size('>=', 100)
->size('<=', 200);
La méthode date()
filtre par date de dernière modification du fichier. Les valeurs peuvent être absolues ou
relatives à la date et à l'heure actuelles, par exemple, de cette manière, nous trouvons les fichiers modifiés au cours des
deux dernières semaines :
Finder::findFiles('*.php')
->date('>', '-2 weeks')
->from($dir)
Les deux fonctions comprennent les opérateurs >
, >=
, <
, <=
,
=
, !=
, <>
.
Finder permet également de filtrer les résultats à l'aide de fonctions personnalisées. La fonction reçoit comme paramètre
l'objet Nette\Utils\FileInfo
et doit retourner true
pour que le fichier soit inclus dans les
résultats.
Exemple : recherche de fichiers PHP qui contiennent la chaîne Nette
(indépendamment de la casse) :
Finder::findFiles('*.php')
->filter(fn($file) => strcasecmp($file->read(), 'Nette') === 0);
Filtrage en profondeur
Lors de la recherche récursive, vous pouvez définir la profondeur maximale de parcours à l'aide de la méthode
limitDepth()
. Si vous définissez limitDepth(1)
, seuls les premiers sous-répertoires sont parcourus,
limitDepth(0)
désactive le parcours en profondeur et la valeur –1 annule la limite.
Finder permet, à l'aide de fonctions personnalisées, de décider dans quel répertoire entrer lors du parcours. La fonction
reçoit comme paramètre l'objet Nette\Utils\FileInfo
et doit retourner true
pour entrer dans le
répertoire :
Finder::findFiles('*.php')
->descentFilter($file->getBasename() !== 'temp');
Tri
Finder offre également plusieurs fonctions pour trier les résultats.
La méthode sortByName()
trie les résultats par noms de fichiers. Le tri est naturel, c'est-à-dire qu'il gère
correctement les nombres dans les noms et retourne par exemple foo1.txt
avant foo10.txt
.
Finder permet également de trier à l'aide d'une fonction personnalisée. Celle-ci reçoit comme paramètre deux objets
Nette\Utils\FileInfo
et doit retourner le résultat de la comparaison avec l'opérateur <=>
,
c'est-à-dire -1
, 0
ou 1
. Par exemple, de cette manière, nous trions les fichiers par
taille :
$finder->sortBy(fn($a, $b) => $a->getSize() <=> $b->getSize());
Plusieurs recherches différentes
Si vous avez besoin de trouver plusieurs fichiers différents à différents emplacements ou répondant à d'autres critères,
utilisez la méthode append()
. Elle retourne un nouvel objet Finder
, il est donc possible d'enchaîner
les appels de méthodes :
($finder = new Finder) // nous stockons le premier Finder dans la variable $finder !
->files('*.php') // dans src/, nous recherchons les fichiers *.php
->from('src')
->append()
->files('*.md') // dans docs/, nous recherchons les fichiers *.md
->from('docs')
->append()
->files('*.json'); // dans le dossier actuel, nous recherchons les fichiers *.json
Alternativement, il est possible d'utiliser la méthode append()
pour ajouter un fichier spécifique (ou un
tableau de fichiers). Elle retourne alors le même objet Finder
:
$finder = Finder::findFiles('*.txt')
->append(__FILE__);
FileInfo
Nette\Utils\FileInfo est une classe représentant un fichier ou un répertoire dans les résultats de la recherche. Il s'agit d'une extension de la classe SplFileInfo, qui fournit des informations telles que la taille du fichier, la date de dernière modification, le nom, le chemin, etc.
De plus, elle fournit des méthodes pour retourner le chemin relatif, ce qui est utile lors du parcours en profondeur :
foreach (Finder::findFiles('*.jpg')->from('.') as $file) {
$absoluteFilePath = $file->getRealPath();
$relativeFilePath = $file->getRelativePathname();
}
De plus, vous avez à disposition des méthodes pour lire et écrire le contenu du fichier :
foreach ($finder as $file) {
$contents = $file->read();
// ...
$file->write($contents);
}
Retour des résultats sous forme de tableau
Comme on l'a vu dans les exemples, Finder implémente l'interface IteratorAggregate
, vous pouvez donc utiliser
foreach
pour parcourir les résultats. Il est programmé de telle sorte que les résultats sont chargés uniquement
pendant le parcours, donc si vous avez une grande quantité de fichiers, on n'attend pas que tous soient lus.
Vous pouvez également faire retourner les résultats sous forme de tableau d'objets Nette\Utils\FileInfo
, et ce,
par la méthode collect()
. Le tableau n'est pas associatif, mais numérique.
$array = $finder->findFiles('*.php')->collect();