Discover autoloadable PHP classes from directories.
- Requires PHP 8.4+
- No runtime dependencies
composer require northrook/php-class-finderPoint the finder at your project root, scan one or more directories, then filter by attribute:
use Northrook\ClassFinder;
$finder = new ClassFinder(__DIR__);
$services = $finder
->scanDirectories('src/*')
->anyAttribute(App\Attribute\Service::class);
foreach ($services as $classInfo) {
$instance = $classInfo(); // instantiate via __invoke
}ClassFinder resolves paths relative to the root directory.
Append * for recursive scanning (src/*); omit it to scan only the immediate directory (src).
Walks .php files, parses for class declaration, only accepting autoloadable classes.
Results are keyed by the absolute file path.
This is lightweight: no full AST parsing, and files are not blindly required. Kept classes are confirmed via the autoloader (class_exists), which does load them.
Intended for cold-path operations, like bootstrapping DI containers, route discovery, etc.
class,abstract class,final class, andreadonlyvariants- Classes in the global namespace
- Classes with attributes on preceding lines (including multiline
#[...])
- Hidden files, prefixed with
. - Non-
.phpfiles - Interfaces, enums, and traits
- Files with no class definition
- A second
classin the same file (only the first is read, as per PSR-4) - Classes that are not autoloadable
- Code after an early
return,exit, ordie - Namespaces listed in
excludeNamespaces()(defaults toComposer)
Entry point. Configure the root path and namespace exclusions, then scan.
$finder = new ClassFinder('/path/to/project');
$finder->excludeNamespaces('Vendor\\Generated', 'Tests');
$scan = $finder->scanDirectories('src/*', 'config');| Member | Description |
|---|---|
$rootDirectory |
Normalized absolute path passed to the constructor |
$lastScan |
Most recent ClassScan, or null |
excludeNamespaces(...) |
Replace excluded namespaces; no arguments resets to ['Composer'] |
scanDirectories(...) |
Scan directories relative to the root; returns ClassScan |
normalizePath() |
Collapse mixed separators into an absolute-style path |
Immutable scan result. Iterable and countable; values are ClassInfo instances.
$scan = $finder->scanDirectories('src/*');
$scan->count();
$scan->getArray(); // [filePath => ClassInfo]
$scan->anyAttribute(Foo::class, Bar::class); // classes with at least one match
$scan->withAttributes(Foo::class, Bar::class); // classes with every attributeanyAttribute() and withAttributes() use exact attribute class names.
For inheritance-aware matching, use ClassInfo::getAttributes() on individual results.
Metadata and reflection helpers for a single class.
use Northrook\ClassFinder\ClassInfo;
$info = ClassInfo::from(SomeService::class);
$info->className; // FQCN
$info->basename; // short name
$info->namespace; // namespace without short name
$info->file; // absolute path to the defining file
$info->reflection; // lazy ReflectionClass
$info->hasAttribute(Service::class); // exact match
$info->getAttributes(Service::class); // includes subclasses (IS_INSTANCEOF)
$info->getAttribute(Service::class); // single instance, or null
$info( ...$args ); // instantiate the class
ClassInfo::basename($class, 'strtolower');
ClassInfo::exists('Some\\Class');composer test
composer phpstanBSD-3-Clause. See LICENSE.md.