Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Php File Iterator Laravel Package

phpunit/php-file-iterator

php-file-iterator provides a simple, dependency-free way to filter and iterate over files by suffix, prefix, or custom filters, powering PHPUnit's test file discovery. Install it via Composer to find and list files matching patterns in any PHP project.

View on GitHub
Deep Wiki
Context7

Getting Started

You almost certainly already have this package. It arrives transitively through phpunit/phpunit (PHPUnit's test discovery uses it to expand <directory> / <exclude> nodes in phpunit.xml), so the first step is not composer require but confirming what you've got:

composer show phpunit/php-file-iterator   # version + dependents
composer why phpunit/php-file-iterator    # who actually pulls it in

Look at vendor/phpunit/php-file-iterator/src/ first — the public surface is tiny (Factory, Iterator, and a couple of path-filter classes), and the constructor signatures have shifted across 5.x → 6.x → 7.x, so the source is more reliable than any blog post (including the snippet below).

Only add it as a direct dev dependency if your own code calls it. If you're just writing application features, use Symfony\Component\Finder\Finder — it ships with Laravel already and is the idiomatic choice. The realistic first use case for a Laravel dev is tooling: enumerating test files the same way PHPUnit does, so your custom script and your phpunit.xml agree on what "the test suite" means.

use PHPUnit\File\Iterator\Factory;

$files = (new Factory)->getFileIterator(
    [base_path('tests')],           // paths to traverse
    ['php'],                        // suffixes
    [],                             // prefixes
    [base_path('tests/Fixtures')],  // excluded paths
);

foreach ($files as $file) {
    echo $file->getPathname(), PHP_EOL;
}

Verify the exact method name against your installed version before copying — getFileIterator() vs getIterator() has changed, and the class moved to PHPUnit\File\Iterator\Factory.

Implementation Patterns

Understand your phpunit.xml before reaching for the class. The <directory suffix=".php">, <exclude>, <prefix>, and glob patterns in your testsuite config are compiled by PHPUnit into exactly these constructor arguments. When a test file mysteriously isn't running, reading the iterator's semantics is faster than guessing:

<testsuite name="Unit">
    <directory suffix="Test.php">tests/Unit</directory>
    <exclude>tests/Unit/Fixtures</exclude>
</testsuite>

Globstar for multi-directory suites. Since 5.1.0, ** is supported — useful when you want tests/**/*Test.php without listing every nested folder. Reach for Factory (not Iterator) whenever you're passing patterns rather than plain paths.

CI test sharding. This is the most defensible day-to-day use in a Laravel app: splitting the test suite across parallel CI jobs using the same file list PHPUnit would build.

$files = iterator_to_array(
    (new Factory)->getFileIterator([base_path('tests')], ['php'])
);

$shard = array_values(array_filter(
    $files,
    fn ($file) => crc32($file->getPathname()) % $total === $index
));

Custom Artisan commands. For "lint all PHP files" or "scan for a pattern" commands, the pattern is: use php-file-iterator only if you specifically need PHPUnit-identical filtering; otherwise Finder::files()->name('*.php')->in(...). Wrapping the iterator in a small service class keeps the dependency swappable if you later migrate to Finder.

Don't chain on the instance in a loop. The iterator/filter wrappers are effectively immutable — each add*()/filter call returns a new instance, so building the filter once outside a loop matters for anything non-trivial.

Extending. For content-based or custom rules, subclass FilterIterator (SPL) directly and implement accept(). Don't try to bolt content inspection onto the suffix/prefix filters.

Gotchas and Tips

  • Version lock-step with PHPUnit. PHPUnit pins a specific major of this package, and each major drops a PHP minor (7.x dropped PHP 8.3 support; 6.x dropped 8.2). If you composer require --dev phpunit/php-file-iterator:^5 while PHPUnit wants ^6, you get a conflict. Let PHPUnit choose the version unless you have a hard reason not to.
  • Hidden directories and Windows separators. 7.0.1 changed hidden directories to be pruned rather than traversed-and-discarded, and fixed hidden-directory filtering on Windows where only / was recognized. If you're on < 7.0.1 with Windows CI, expect inconsistency between local and CI runs.
  • Exclusion is prefix-based on directories, not gitignore semantics — 7.0.2 fixed a bug where paths merely sharing a prefix with an excluded directory were wrongly excluded. If you're on an older release, tests/Fixtures can silently swallow tests/FixturesExtra.
  • Unreadable directories. Before 7.0.2, a single unreadable directory aborted the entire traversal. On older versions, guard with is_readable() or expect partial listings in containerized CI where permissions are odd.
  • Globstar needs separators. src/**/*.php works; **.php does not. Also, 7.0.1 fixed **-leading patterns resolving incorrectly — test your pattern against a real tree rather than trusting the docs.
  • Path resolution. 7.0.1 stopped realpath()-ing every file for prefix/suffix filtering. If you depend on absolute, symlink-resolved paths, call realpath() yourself — don't assume getPathname() is normalized, especially on macOS with /var → /private/var.
  • Lazy iteration. It's a FilterIterator; nothing is scanned until you iterate, and exceptions surface mid-loop. Convert with iterator_to_array() early if you need to count or sort.
  • Don't ship it in production code paths. It's a dev-time, PHPUnit-internal utility with no stability promise across majors. Keep direct usage inside tests/, tools/, or CI scripts, and prefer Symfony Finder (already a Laravel dependency) for anything runtime-facing — that also avoids a transitive-dependency upgrade breaking your feature because PHPUnit bumped a major.
  • Debugging tip: when a file is missing from a run, don't instrument the iterator — bin/phpunit --list-tests (or --testsuite) shows the resolved list directly, which is the same traversal output with none of the setup code.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console