Parcourir les fichiers c’est simple avec PHP 5 et la SPL. Ou pas.
<?php class bigFileFilterIterator extends FilterIterator { public function accept() { $oFileInfo = $this->getInnerIterator()->current(); return ($oFileInfo->getSize() > 10000); } } $themedir = __DIR__.'/theme'; $iterator = new RecursiveDirectoryIterator($themedir, FilesystemIterator::SKIP_DOTS); $iterator->setFlags(FilesystemIterator::CURRENT_AS_FILEINFO); $recursiveIterator = new RecursiveIteratorIterator($iterator); foreach(new bigFileFilterIterator($recursiveIterator) as $file) { echo $file->getfilename()."n"; }
Sérieusement ? Mais pourquoi ne puis-je pas utiliser directement le RecursiveDirectoryIterator et dois-je instancier un RecursiveIteratorIterator ? Celui qui a conçu cette dernière classe souffre-t-il de bégayement ? Rien que l’instanciation du premier itérateur ne tient pas sur une seule ligne. Un ->getInnerIterator()->current() et pas un paramètre directement dans la méthode ->accept() ? Sérieusement ?
Montrer les nouvelles possibilités c’est appréciable, les qualifier de simple est une insulte à l’intelligence.
De mon temps on faisait quelque chose comme ce qui suit :
<?php function recursive_filter($path) { $dir = dir($path) ; while (false !== ($name = $dir->read())) { if ($name[0] === '.') return ; $new_path = $path.DIRECTORY_SEPARATOR.$name ; if (is_dir($new_path)) { recursive_filter($new_path) ; } elsif (file_size($new_path) > 10000) { echo $new_path ; } } } $themedir = __DIR__.'/theme'; recursive_filter( $themedir ) ;
Ce n’était pas plus court, mais pas plus long. On peut entrer dans de longs discours pour savoir si c’était plus simple ou plus complexe, mieux structuré ou non, mais la valeur ajoutée du nouveau code ne saute pas aux yeux côté simplicité je trouve.
À titre d’exemple, en ruby (« find » est dans la lib standard) :
require 'find' theme_dir = File.dirname(__FILE__)."/theme" Find.find(theme_dir) do |path| next if FileTest.directory?(path) puts path if FileTest.size(path) > 10000 end
Ou sur Python :
import os themedir = os.path.join(os.path.dirname(__file__), "theme") def find_files(directory): for root, dirs, files in os.walk(directory): for basename in files: if not file.startswith("."): filename = os.path.join(root, basename) yield filenames for filename in find_file(themedir) if os.path.getsize(filename) > 10000 : print filename
Il peut y avoir des fautes et il peut y avoir mieux dans les différents langages, et peu importe le nombre de lignes, mais dans les quatre codes précédents c’est bien le premier qui me semble complexe.
Il y a bien d’autres occasions de trouver PHP « simple », mais pas les itérateurs de la SPL.
5 réponses à “Parcourir des dossiers et filtrer les fichiers n’a jamais été aussi simple avec la SPL de PHP5”
En Perl, l’équivalent du code Ruby que tu as posté :
use Path::Class;
my $dir = dir(__FILE__, ‘theme’);
while (my $file = $dir->next) {
next if $file->is_dir;
say $file if $file->stat->size > 10000;
}
Note:
$dir et $file sont des objets répertoire et fichiers respectivement, qui ont la bonne idée de renvoyer le path quand ils sont interprété en tant que chaîne.
Salut Eric
Regarde du côté de https://github.com/symfony/Finder ;)
Éric,
Lorsque j’ai cliqué sur le lien de ton billet, je m’attendais à une critique du billet ayant servi de point de départ en bonne et due forme, mais à mon grand regret, ça n’a pas été le cas.
En effet, prendre pour argent comptant le contenu d’un billet de blog pour ensuite faire du bashing facile est tout autant une insulte à l’intelligence, car le code qui t’a servi de base aurait dut être écrit de la manière suivante : https://gist.github.com/3944632
Certes, cela reste verbeux et il est toujours possible de pester contre un certain nombre de choses (comme effectivement l’usage obligatoire de recursiveIteratorIterator qui me sort tout autant par les yeux que toi) mais cette version est tout de même nettement plus simple, plus lisible et au final pas mal éloignée de celle qui t’a servie de base pour ton argumentaire (et en prime, on peut passer des arguments à la méthode accept()).
Certes, pour obtenir ce résultat, il faut avoir lu (ou avoir pris la peine de le faire…) la documentation de la SPL, en avoir compris les mécanismes et avoir une bonne connaissance des arguments par défaut des différentes méthodes, mais n’est ce pas le le travail de tout bon développeur ?
Je sais que le bashing de PHP est à la mode, souvent avec raison mais aussi parfois à tort, et j’avoue être surpris que tu sois tombé dans facilité sur ce coup.
je crois que j’ai été mal compris Frédéric. Je critique plus le billet de blog que PHP lui-même ici : Mon problème c’est montrer un code complexe et le qualifier de simple lors de la présentation.
Les codes des autres langages ne sont là que pour montrer d’autres façons de faire, pas pour dire « PHP c’est nul ». Oui je trouve que la SPL a une tendance claire à sur-architecturer et copier les architectures Java, mais ce n’était pas le sujet ici. Si tu y vois du bashing PHP ça renforce plutôt mon discours.
Ton code est effectivement beaucoup plus lisible. J’ai encore les deux points de mon premier paragraphe qui me sortent par les yeux (mais visiblement le premier te gène aussi) et qui me bloquent, mais si ça avait été présenté ainsi je n’aurai peut être pas fait de billet.
Je pense que les comparaisons avec les autres langages m’ont induit en erreur, et du coup, j’ai sorti les crocs apparemment trop rapidement.
Reste que la SPL, même si elle n’est pas exempte de défaut, bien au contraire, est un superbe outil qui permet d’écrire rapidement et simplement du code fiable pour des opérations courantes mais potentiellement complexes à coder (un parcours récursif n’est pas forcément la chose la plus évidente au monde), à la condition qu’elle soit correctement maîtrisée, ce qui n’est visiblement pas le cas de l’auteur du billet de départ.
C’est un peu comme goto (pas taper), finaly (celui, je pense qu’il va poser quelques problèmes intéressants) ou les namespaces, ça permet de faire le pire comme le meilleur, en fonction des compétences du programmeur.