Just came across a Youtube talk "Iterators in PHP" by Jake Smith published in 2014 that steps through the many different Iterators and some practical examples.
I have reproduced many of the examples Jake used below, running them with PHP 8.1.5 and published the code at https://github.com/toggenation/iterator-training
I also found a short and clearly explained video about Iterators by Dr Adam Nielson which was helpful too. Watch this one first as it's a bit of a primer.
An Important Point About the RecursiveIterators. They require RecursiveIteratorIterator!
You can't just use one of the Recursive*Iterators without wrapping it in RecursiveIteratorIterator if you do use it on its own it will not recurse down the tree
- RecursiveArrayIterator
- RecursiveCachingIterator
- RecursiveCallbackFilterIterator
- RecursiveDirectoryIterator
- RecursiveFilterIterator
- RecursiveIteratorIterator <== Wrap there rest of these with this.
- RecursiveRegexIterator
- RecursiveTreeIterator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <?php$rdi = new RecursiveDirectoryIterator('/var/www/wms/webroot', FilesystemIterator::SKIP_DOTS);$rii = new RecursiveIteratorIterator($rdi, RecursiveIteratorIterator::CHILD_FIRST);// now ready to walk the entire tree below the specified rootforeach ($rii as $file) { /** * @var SplFileInfo $file */ echo $file->getPathname(), "\n";}/*/var/www/wms/webroot/img/x-lg.svg/var/www/wms/webroot/img/TOGGEN-LOGO.svg/var/www/wms/webroot/img/toggen-logo-122x27.png/var/www/wms/webroot/img/down-arrow.svg/var/www/wms/webroot/img/100pbc-bottling-company.png/var/www/wms/webroot/img/test-error-icon.png/var/www/wms/webroot/img/cake.logo.svg/var/www/wms/webroot/img/TOGGEN-GOAT.svg/var/www/wms/webroot/img/test-fail-icon.png/var/www/wms/webroot/img/var/www/wms/webroot/phpinfo.php/var/www/wms/webroot/.htaccess */ |
CachingIterator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <?php// CachingIterator aka LookAhead Iterator$animals = ['Cat', 'Dog', 'Shark', 'Elephant', 'Tiger', 'Lion', 'Bear', 'Donkey', 'Sheep'];$collection = new CachingIterator(new ArrayIterator($animals));var_dump($collection->current()); // nullvar_dump($collection->getInnerIterator()->current()); // Catforeach ($collection as $animal) { echo "Current: {$animal}"; if ($collection->hasNext()) { echo ' - Next:' . $collection->getInnerIterator()->current(); } echo PHP_EOL;}/** * output * * Current: Cat - Next:Dog * Current: Dog - Next:Shark * Current: Shark - Next:Elephant * Current: Elephant - Next:Tiger * Current: Tiger - Next:Lion * Current: Lion - Next:Bear * Current: Bear - Next:Donkey * Current: Donkey - Next:Sheep * Current: Sheep */ |
CallBackIterator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <?php$dirIt = new GlobIterator('/var/www/wms/tmp/*.csv');$recursiveFiles = new CallbackFilterIterator( $dirIt, function ($current, $key, $it) { return preg_match('|test627|i', $current); });foreach ($recursiveFiles as $name) { echo $name . PHP_EOL;}echo iterator_count($recursiveFiles) . PHP_EOL;/** * output * /var/www/wms/tmp/TEST627b509d5ac743.01130673.csv * /var/www/wms/tmp/TEST627b52ac03dad4.63971256.csv * /var/www/wms/tmp/TEST627b53a94454a9.12415465.csv * /var/www/wms/tmp/TEST627b54cdee2a88.20247776.csv * /var/www/wms/tmp/TEST627b55a2530101.43769565.csv * /var/www/wms/tmp/TEST627b5643c63625.69582969.csv * 6 */ |
DirectoryIterator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | <?php$it = new DirectoryIterator('/var/www/wms/src');foreach ($it as $file) { if ($file->isDot()) { continue; } if ($file->isFile()) { echo "FILE:::: {$file->getFilename()}" . PHP_EOL; } if ($file->isDir()) { echo "DIR:::: {$file->getFilename()}" . PHP_EOL; } echo $file->getFilename() . PHP_EOL;}/** * output * * DIR:::: Command * Command * DIR:::: Log * Log * DIR:::: Routing * Routing * DIR:::: Job * Job * DIR:::: Lib * Lib * DIR:::: Model * Model * DIR:::: React * React * DIR:::: View * View * DIR:::: Middleware * Middleware * FILE:::: Application.php * Application.php * DIR:::: Listener * Listener * DIR:::: Error * Error * DIR:::: Policy * Policy * DIR:::: Console * Console * DIR:::: Form * Form * DIR:::: Controller * Controller * DIR:::: Mailer * Mailer */ |
FileSystemIterator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | <?php// filesystem iterator has skip dots on by default$it = new FilesystemIterator('/var/www/wms/src');foreach ($it as $file) { // not required // if ($file->isDot()) { // continue; // } // if ($file->isFile()) { // echo "{$file->getFilename()}" . PHP_EOL; // } // if ($file->isDir()) { // echo "DIR:::: {$file->getFilename()}" . PHP_EOL; // } echo $file->getFilename() . PHP_EOL;}// Output/**CommandLogRoutingJobLibModelReactViewMiddlewareApplication.phpListenerErrorPolicyConsoleFormControllerMailer */ |
LargeImageFilter and NoCVSFilter Custom Filter and RecursiveFilterIterator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | <?phpclass RecursiveNoVCSIterator extends RecursiveFilterIterator{ public function accept(): bool { $vcsFolders = ['.git', '.github', '.svn', '.vscode', '.cache']; /** * @var SplFileInfo $file File Info */ $file = $this->current(); if ($file->isDir() && in_array($file->getFilename(), $vcsFolders)) { return false; }; return true; }}$dirs = new RecursiveDirectoryIterator('/var/www/wms', FilesystemIterator::SKIP_DOTS);$filter = new RecursiveNoVCSIterator($dirs);$recurseIt = new RecursiveIteratorIterator($filter, RecursiveIteratorIterator::SELF_FIRST);// foreach ($recurseIt as $path => $info) {// /**// * @var SplFileInfo $info Info// */// echo $info->getPathname() . PHP_EOL;// }class LargeImageFilter extends FilterIterator{ private array $safeImageTypes = ['png']; private int $fileSize; public function __construct(Iterator $it, $imageTypes, $fileSize = 50000) { parent::__construct($it); if (!empty($imageTypes)) { $this->safeImageTypes = $imageTypes; } $this->fileSize = $fileSize; } public function accept(): bool { $file = $this->current(); if (in_array($file->getExtension(), $this->safeImageTypes) && $file->getSize() > $this->fileSize) { return true; } return false; }}$dirs = new DirectoryIterator('/var/www/wms/webroot/files/templates');$filter = new LargeImageFilter($dirs, [ 'png', 'jpeg'], 30000);foreach ($filter as $file) { echo $file . ': ' . $file->getSize() . PHP_EOL;}echo iterator_count($filter) . PHP_EOL; |
Generators
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | <?php// genoratorfunction abc(){ yield 1; yield 2; yield 3;}echo "Generator\n";foreach (abc() as $num) { echo $num . PHP_EOL;}// stop a generatorfunction rabc(){ yield 1; return; // don't use a return value yield 2; yield 3;}echo "Stopped Generator\n";foreach (rabc() as $num) { echo $num . PHP_EOL;}// Output/*Generator123Stopped Generator1*/ |
GlobIterator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <?phpecho "*.php\n";$it = new GlobIterator('/var/www/wms/webroot/*.php');;foreach ($it as $path => $file) { echo $path . ' - ' . $file->getFilename() . PHP_EOL;}echo "*.txt\n";$it = new GlobIterator('/var/www/wms/webroot/*.txt');;foreach ($it as $path => $file) { echo $path . ' - ' . $file->getFilename() . PHP_EOL;}// Output/**.php/var/www/wms/webroot/index.php - index.php/var/www/wms/webroot/info.php - info.php/var/www/wms/webroot/phpinfo.php - phpinfo.php*.txt/var/www/wms/webroot/htaccess.txt - htaccess.txt*/ |
InfiniteIterator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <?php$data = [1, 2, 3];// as it's name implies it rewinds the pointer to the start// and keeps going forever$it = new InfiniteIterator(new ArrayIterator($data));$ctr = 0;foreach ($it as $i) { $ctr++; // do this or it will go on forever if ($ctr === 10000) die; echo "{$i} - {$ctr}" . PHP_EOL;}// Output/*// ... forever...2 - 99953 - 99961 - 99972 - 99983 - 9999*/ |
LimitIterator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | <?phprequire '../../vendor/autoload.php';use Faker\Factory;$page = 5;$perPage = 10;$resultOffset = ($page * $perPage) - $perPage;$faker = Faker\Factory::create();for ($i = 0; $i < 125; $i++) { $words[]['name'] = $faker->word() . ' ' . $i;}$it = new ArrayIterator($words);try { foreach (new LimitIterator($it, $resultOffset, $perPage) as $result) { echo "{$result['name']}\n"; }} catch (OutOfBoundsException $e) { echo "No Records Found" . PHP_EOL;} catch (Exception $e) { echo $e->getMessage();}// Output /*ullam 40harum 41deleniti 42est 43molestiae 44aut 45enim 46molestias 47placeat 48molestiae 49*/ |
Extending RecursiveIteratorIterator to create a HTML Menu
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | <?phpuse Enqueue\Router\Recipient;$menu = [ 'Home', 'Register', 'About' => [ 'The Team', "Our Story", ], 'Contact' => [ 'Locations', 'Support', ]];class HookRecursiveIteratorIterator extends RecursiveIteratorIterator{ public function beginChildren(): void { // echo __METHOD__ . PHP_EOL; echo '<ul data-where="beginChildren">', PHP_EOL; } public function endChildren(): void { // echo __METHOD__ . PHP_EOL; echo '</ul></li>', "\n"; }}$it = new HookRecursiveIteratorIterator( new RecursiveArrayIterator($menu), RecursiveIteratorIterator::SELF_FIRST);ob_start();echo '<ul>', "\n";foreach ($it as $k => $v) { /** * @var RecursiveIterator $it */ if ($it->hasChildren()) { echo "<li>{$k}\n"; continue; } echo "<li>{$v}</li>\n";}echo "</ul>\n";$html = ob_get_clean();$config = [ 'indent' => true, 'output-xhtml' => false, 'wrap' => 200, 'show-body-only' => true, 'clean' => true,];// Tidy$tidy = new tidy;$tidy->parseString($html, $config, 'utf8');$tidy->cleanRepair();// Outputecho $tidy . PHP_EOL;// Output/*<ul> <li>Home </li> <li>Register </li> <li>About <ul data-where="beginChildren"> <li>The Team </li> <li>Our Story </li> </ul> </li> <li>Contact <ul data-where="beginChildren"> <li>Locations </li> <li>Support </li> </ul> </li></ul>*/ |
ParentIterator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | <?php$rdi = new RecursiveDirectoryIterator('/var/www/wms/src');// only iterates nodes with children// ie. directories are parents// in this case it iterates directories$dirsOnly = new ParentIterator($rdi);$iter = new RecursiveIteratorIterator( $dirsOnly, RecursiveIteratorIterator::CHILD_FIRST);foreach ($iter as $dir) { echo $dir . PHP_EOL;}// Output// Note CHILD_FIRST shows the deepest folders in the tree first/*/var/www/wms/src/React/shipment-app/var/www/wms/src/React/put-away/public/var/www/wms/src/React/put-away/src/var/www/wms/src/React/put-away/var/www/wms/src/React/var/www/wms/src/View/Helper/var/www/wms/src/View/Cell/var/www/wms/src/View/var/www/wms/src/Middleware/UnauthorizedHandler/var/www/wms/src/Middleware/var/www/wms/src/Listener/var/www/wms/src/Error/var/www/wms/src/Policy/var/www/wms/src/Console/var/www/wms/src/Form/var/www/wms/src/Controller/Component/var/www/wms/src/Controller/var/www/wms/src/Mailer*/ |
Using RecursiveDirectoryIterator to mass delete files and/or Folders
I have modified this so it not only deletes files but folders also. Caution you can destroy your file system if you specifiy the wrong Directory.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <?php$it = new RecursiveIteratorIterator( new RecursiveDirectoryIterator('/var/www/wms/logs', FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST);// run out of memory trying to convert the iterator// to an array// var_dump(iterator_to_array($it));// echo print_r(iterator_to_array($it), true);// array_map('unlink', iterator_to_array($it));// this allows it to run without running out of memoryforeach ($it as $k => $v) { if ($it->hasChildren()) { echo "Has Children " . $k . "\n"; rmdir($k); continue; } echo "Deleting $k"; unlink($k);} |
RecursiveTreeIterator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | <?php$it = new RecursiveDirectoryIterator('/var/www/wms/webroot', FilesystemIterator::SKIP_DOTS);foreach (new RecursiveTreeIterator($it) as $path => $file) { echo $file . "\n";}$menu = [ 'Home', 'Register', 'About' => [ 'The Team', "Our Story", ], 'Contact' => [ 'Locations', 'Support', ]];$data = new RecursiveArrayIterator($menu);$it = new RecursiveTreeIterator($data);$it->setPrefixPart( RecursiveTreeIterator::PREFIX_LEFT, '//');$it->setPrefixPart( RecursiveTreeIterator::PREFIX_RIGHT, '||');foreach ($it as $nav) { echo $nav . PHP_EOL;}// Default output/*| | |-/var/www/wms/webroot/files/templates/200x150-Product-Sample-Label.png| | |-/var/www/wms/webroot/files/templates/5-CartonLabel.txt| | |-/var/www/wms/webroot/files/templates/Screen Shot 2022-02-11 at 11.18.47 am.png| | |-/var/www/wms/webroot/files/templates/69-NoBarcode3DigitQtySSCCPalletLabel.txt| | |-/var/www/wms/webroot/files/templates/200x150-Product-Sample-Label.glabels| | \-/var/www/wms/webroot/files/templates/100x50custom-1.glabels| |-/var/www/wms/webroot/files/edi| | \-/var/www/wms/webroot/files/edi/send| | |-/var/www/wms/webroot/files/edi/send/outbound| | \-/var/www/wms/webroot/files/ed* i/send/inbound| |-/var/www/wms/webroot/files/daily_reports| | |-/var/www/wms/webroot/files/daily_reports/2022-04-_Daily_Shift_Report.pdf| | |-/var/www/wms/webroot/files/daily_reports/2022-04-14_Daily_Shift_Report.pdf| | |-/var/www/wms/webroot/files/daily_reports/2022-05-05_Daily_Shift_Report.pdf| | |-/var/www/wms/webroot/files/daily_reports/20_Daily_Shift_Report.pdf */// With prefixes modified/*/|-||Home//|-||Register//|-||Array//| |-||The Team//| \-||Our Story//\-||Array// |-||Locations// \-||Support*/ |
RegexIterator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <?php$a = new ArrayIterator(['test1', 'test2', 'test3', 'test4', 'aaa']);$it = new RegexIterator( $a, '/^(test)(\d)+/', RegexIterator::REPLACE);$it->replacement = '$2:$1';foreach ($it as $el) { echo $el . PHP_EOL;}// Output/*1:test2:test3:test4:test*/ |

0 Comments