Rekurzivní glob()
Funkci glob mám v oblibě, ale chybí mi u ní modifikátor pro rekurzivní procházení adresářů. Toho by se nejspíš dalo nějak dosáhnout zkombinováním tříd RecursiveDirectoryIterator, RecursiveIteratorIterator a GlobIterator, ale přišlo mi to tak krkolomné, že jsem si raději napsal funkci použitelnou se stejnou lehkostí jako původní glob:
<?php /** Nalezení souborů vyhovujících dané masce ve všech podadresářích * @param string se stejnými zástupnými znaky jako glob() * @param int stejné jako glob() * @return array nalezené soubory * @copyright Jakub Vrána, https://php.vrana.cz/ */ function rglob($pattern, $flags = 0) { $return = glob($pattern, $flags); $dirs = "*"; $separator = DIRECTORY_SEPARATOR; $files = $pattern; if (preg_match('~(.*)([/\\\\])(.+)~', $pattern, $match)) { $dirs = "$match[1]$match[2]*"; $separator = $match[2]; $files = $match[3]; } foreach (glob($dirs, ($flags & ~GLOB_MARK) | GLOB_ONLYDIR) as $subdir) { $return = array_merge($return, rglob("$subdir$separator$files", $flags)); } return $return; } ?>
Funkce si poradí se všemi obvyklými vstupy:
- *.xml
- dir/*.xml
- dir*/*.xml
Dbá také na to, aby byl výstup konzistentní: pokud jí předáte dir/*.xml, tak na Windows nevrátí dir/subdir\a.xml. Stejně tak pro *.xml nevrátí ./a.xml. Kvůli tomu je trochu složitější, než by na první pohled mělo být potřeba.
Zásadní nevýhodou této funkce je, že nejprve získá seznam všech souborů, uloží ho do paměti a pak je teprve můžeme procházet. Vzhledem k mému nejobvyklejšímu využití této funkce (jednorázové skripty spouštěné z příkazové řádky) mi to ale nevadí. Vyřešit by se to dalo přepsáním na iterátor. S podporou operátoru yield (v HipHopu pro PHP nebo v PHP 5.5) by to vypadalo skoro stejně:
<?php
/** Nalezení souborů vyhovujících dané masce ve všech podadresářích
* @param string se stejnými zástupnými znaky jako glob()
* @param int stejné jako glob()
* @return array nalezené soubory
* @copyright Jakub Vrána, https://php.vrana.cz/
*/
function rglob_yield($pattern, $flags = 0) {
	foreach (glob($pattern, $flags) as $filename) {
		yield $filename;
	}
	$dirs = "*";
	$separator = DIRECTORY_SEPARATOR;
	$files = $pattern;
	if (preg_match('~(.*)([/\\\\])(.+)~', $pattern, $match)) {
		$dirs = "$match[1]$match[2]*";
		$separator = $match[2];
		$files = $match[3];
	}
	foreach (glob($dirs, ($flags & ~GLOB_MARK) | GLOB_ONLYDIR) as $subdir) {
		foreach (rglob_yield("$subdir$separator$files", $flags) as $filename) {
			yield $filename;
		}
	}
}
foreach (rglob_yield('www/api/*.php') as $filename) {
	echo "$filename\n";
}
?>
Nejjednodušší funkce pro rekurzivní glob():
<?php /** Nalezení souborů vyhovujících dané masce ve všech podadresářích * @param string se stejnými zástupnými znaky jako glob() * @return Generator nalezené soubory * @copyright Jakub Vrána, https://php.vrana.cz/ */ function rglob($pattern) { yield from glob($pattern); foreach (glob(dirname($pattern) . "/*", GLOB_ONLYDIR) as $dir) { yield from rglob("$dir/" . basename($pattern)); } } ?>
Diskuse
Michal:
Jenom upozorním na drobnost, v hlavičce druhé funkce:function rglob_yeild($pattern, $flags = 0) {
je překlep y*ei*ld.
hever:
a ještě v druhé funkci nevidím return... Jakub Vrána
 Jakub Vrána   :
: 
To je právě smysl operátoru yield… Místo jednoho return můžu mít více yield.
 Jakub Vrána
 Jakub Vrána   :
: ozz:
`yield return` má c#, že? Jakub Vrána
 Jakub Vrána   :
: 
Díky za upozornění, opravil jsem to.
 Jakub Vrána
 Jakub Vrána   :
: Diskuse je zrušena z důvodu spamu.
 © 2005-2025 Jakub Vrána.
Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení
© 2005-2025 Jakub Vrána.
Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení  .
Můžeme si tykat.
Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset.
Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.
.
Můžeme si tykat.
Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset.
Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.


