Library / SDK
sebastianbergmann/php-file-iterator avatar
sebastianbergmann/php-file-iterator

php-file-iterator: suffix and prefix filtering for PHP file discovery

FilterIterator implementation that filters files based on a list of suffixes, prefixes, and other exclusion criteria.

7,476 stars47 forksPHPBSD-3-Clause

At a glance

What is it?
php-file-iterator is a small FilterIterator that selects files by suffix, prefix and exclusion rules. It is the filtering layer underneath PHPUnit's test discovery, and it is only worth adding to a project that already walks directory trees.
Who is it for?
Add php-file-iterator when you are writing tooling that walks a directory tree and needs the same suffix, prefix and exclusion semantics PHPUnit uses for test discovery. Do not add it for one-off globbing in application code: glob() and RecursiveDirectoryIterator cover that without a dependency.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 25, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem: selecting test files without hardcoding paths

Most PHP projects do not enumerate test files by hand. They point a runner at a directory and let it decide which files count. That decision is a filter, and it has to handle suffixes such as Test.php, directory prefixes, and paths that must be excluded even though they match. Writing that filter inline in every tool produces slightly different rules in each tool, and the differences only surface when a file is silently skipped.

php-file-iterator exists to hold those rules in one place. The README describes it as a FilterIterator implementation that filters files based on a list of suffixes, prefixes, and other exclusion criteria. That is the whole scope. It does not execute tests, parse PHP, or report results. It answers one question: given a set of paths, which of them should the caller look at?

The audience is narrow and specific. You are building a test runner, a static analysis driver, a coverage collector, or an internal script that must reproduce PHPUnit's notion of which files are tests. If you are writing application code that reads one config file, this library is the wrong shape entirely.

How the filtering works: FilterIterator over a path list

The package is built on PHP's Standard PHP Library. FilterIterator is an abstract class that wraps another iterator and calls an accept() method for each element; only elements where accept() returns true are yielded. php-file-iterator supplies that accept() logic, so the data flow is: caller provides paths, the iterator wraps them, and iteration produces the surviving subset.

The repository layout supports this reading. src/ holds the implementation, tests/ holds the test suite, and the top level carries phpunit.xml, phpstan.neon, .php-cs-fixer.dist.php and a build.xml. That is the standard shape of a Sebastian Bergmann library: a small src tree, a PHPUnit suite, static analysis configuration, and a Phing build file. There is no framework, no service container, and no configuration file of its own.

Two consequences follow. First, the object is lazy: nothing is scanned until you iterate, which matters when the caller only needs the first match. Second, the rules are supplied by the caller rather than read from disk, so the same iterator can serve a project that names its tests FooTest.php and one that names them foo.test.php. The trade-off is that the caller must know the rules; the library will not infer your project's conventions.

The related searches around this package mix it up with general PHP iterator topics such as IteratorAggregate, ArrayIterator and generators. Those are different tools. IteratorAggregate lets an object expose an iterator; ArrayIterator wraps an array; a generator is a function that yields values. php-file-iterator is a concrete filter over a path collection, and it is useful only when the input is a file list.

Installing php-file-iterator with Composer

The README gives two Composer commands and nothing else. The first adds the library as a local, per-project dependency; the second marks it as a development-time dependency, which is what you want when the iterator is used solely by a test or analysis tool.

bash
composer require phpunit/php-file-iterator

If the library is only needed during development, for instance to run the project's test suite, the README offers the development-time form instead. Both commands are quoted verbatim, and no version constraint appears in the README, so Composer resolves the current release for your PHP version.

bash
composer require --dev phpunit/php-file-iterator

After installation the class is available through Composer's autoloader. The README documents installation only; it publishes no usage example and no constructor signature, so check src/ in the installed version before relying on argument order. The repository does carry a tests/ directory, and that suite is the authoritative place to see how the released class is instantiated.

Where php-file-iterator stops being the right tool

The library filters paths. It does not discover them. If your entry point is a directory rather than a list, you still need RecursiveDirectoryIterator, Finder, or your own walk to produce the input, and that walk is where most of the complexity lives: symbolic links, permission errors, vendor directories, generated caches.

Exclusion criteria are also not a security boundary. A filter that skips a directory by name will skip it wherever it appears, and a filter that skips by path prefix will not protect you from a symlink pointing elsewhere. If you are building something that must not read outside a root, the check belongs in the filesystem layer, not in a suffix filter.

The third limitation is versioning. The package publishes parallel release lines, with 6.0.2 and 7.0.2 both released on 2026-08-25 according to the release list. The README does not state a PHP version requirement, so the mapping between major version and runtime is something you confirm from composer.json in the version you install. On a codebase pinned to an older PHP, pulling the newest major can be the wrong move.

Finally, this is a library, not a command. There is no CLI, no config file, and no output format. If what you actually want is to run tests, install PHPUnit; php-file-iterator is a component inside it, not a substitute.

Compared with glob() and a hand-written RecursiveFilterIterator

The realistic alternative for most projects is the standard library. glob() with a pattern such as src/*Test.php returns matching paths in one call and needs no dependency at all. For recursive walks, RecursiveDirectoryIterator combined with RecursiveCallbackFilterIterator gives you the same lazy filtering behaviour with code you control.

The difference is not capability but convention. A hand-written filter encodes your rules and drifts as your project grows; php-file-iterator encodes the rules PHPUnit already uses, which means your tooling and your test runner agree on what a test file is. That agreement is the reason to take on the dependency. If your project has no PHPUnit in it and no intention of matching PHPUnit's discovery semantics, glob() is shorter, faster to read, and has nothing to upgrade.

A second alternative is a higher-level finder such as symfony/finder, which offers name patterns, size filters, and depth limits in a fluent API. It solves a broader problem and brings a broader dependency. php-file-iterator is the narrower choice: one filtering concern, no fluent builder, no configuration.

Maintenance, upgrade cost and the BSD-3-Clause licence

The repository is not archived, and the last push was on 2026-08-25, which is recent relative to the releases listed for the same date. The release list shows 7.0.2 and 6.0.2 published minutes apart, which is the pattern of a maintainer backporting a fix to the previous major line rather than abandoning it. That matters if you are stuck on the older line: security and bug fixes are still landing there.

Upgrade cost is low in absolute terms because the public surface is small, but it is not zero. A major version bump in this family of packages typically tracks a PHP version requirement, and the README does not document one. Before upgrading, read composer.json in the target release. The repository also carries renovate.json, which indicates dependency updates are automated on the maintainer's side; that says nothing about your own upgrade path.

The licence is BSD-3-Clause, stated in the repository and in the LICENSE file at the top level. That is a permissive licence: it allows use, modification and redistribution provided the copyright notice and disclaimer are retained. It does not impose copyleft obligations on your code. This is a description of the licence text, not legal advice; if you are redistributing the library in a product, have your own counsel read LICENSE.

Editorial conclusion

Add php-file-iterator when you are writing tooling that walks a directory tree and needs the same suffix, prefix and exclusion semantics PHPUnit uses for test discovery. Do not add it for one-off globbing in application code: glob() and RecursiveDirectoryIterator cover that without a dependency. Before adopting, verify the installed major version against your PHP runtime, because the package ships separate 6.x and 7.x lines, and confirm which suffixes and prefixes your own discovery code passes in.

Frequently asked questions

What is an iterator in PHP and how is it used?

An iterator is an object you can loop over with foreach, producing one element at a time instead of materialising a whole array. php-file-iterator is a FilterIterator, a standard library iterator that wraps another iterator and yields only the elements its accept() method approves.

What is a PHP file used for?

PHP files are the source files this library filters: the README describes php-file-iterator as filtering files based on a list of suffixes, prefixes, and other exclusion criteria. The library selects which of those files a caller should look at.

What does "iteration" mean in PHP?

Iteration is the act of stepping through a collection one element at a time. In this package, iteration over the file iterator is what triggers the suffix, prefix and exclusion rules, so no filtering work happens until you start the loop.

What will next() do in an iterator?

next() advances an iterator to the following element, and in a FilterIterator that advance continues past elements the filter rejects until it finds one that passes. The README does not document next() for this package, so the behaviour you get is the one inherited from PHP's FilterIterator.

Official sources

  1. Official README
  2. Project repository
  3. Release notes
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/sebastianbergmann-php-file-iterator.svg)](https://hysenlabs.com/projects/sebastianbergmann-php-file-iterator)