kcs/class-finder
Discover and filter PHP classes and namespaces in your project using Composer’s autoloader with PSR resolution. Iterate found classes and reflections, then narrow results by interfaces, subclasses, annotations, PHP 8 attributes, directories, namespaces, or custom callbacks.
Installation Add the package via Composer:
composer require alekitto/class-finder
No additional configuration is required—it’s a drop-in utility.
First Use Case: Finding Classes in a Namespace
Locate all classes under App\Models:
use Alekitto\ClassFinder\ClassFinder;
$finder = new ClassFinder();
$classes = $finder->findClassesInNamespace('App\Models');
foreach ($classes as $class) {
echo $class . "\n";
}
Key Entry Points
ClassFinder::findClassesInNamespace(string $namespace) – Recursively scans a namespace.ClassFinder::findClassesByTrait(string $trait) – Finds classes using a specific trait.ClassFinder::findClassesByInterface(string $interface) – Finds classes implementing an interface.ClassFinder::findClassesUsingMethod(string $method) – Finds classes with a given method signature.Useful for auto-registering services (e.g., event listeners, commands):
$listeners = (new ClassFinder())
->findClassesUsingMethod('handle')
->filter(fn($class) => class_implements($class, EventListener::class));
foreach ($listeners as $listener) {
app()->bindEventListener($listener);
}
Generate test stubs for all classes in a module:
$moduleClasses = (new ClassFinder())
->findClassesInNamespace('App\Modules\Auth')
->filter(fn($class) => !str_contains($class, 'Test'));
foreach ($moduleClasses as $class) {
$testClass = str_replace('\\', '\\Tests\\', $class) . 'Test';
// Generate test stub...
}
Audit classes for deprecated methods:
$classesWithDeprecated = (new ClassFinder())
->findClassesInNamespace('App')
->filter(fn($class) => method_exists($class, 'deprecatedMethod'));
Bootstrapping in AppServiceProvider:
public function boot()
{
$this->registerDynamicCommands();
}
protected function registerDynamicCommands()
{
$commands = (new ClassFinder())
->findClassesUsingMethod('handle')
->filter(fn($class) => is_subclass_of($class, Command::class));
foreach ($commands as $command) {
$this->commands($command);
}
}
Caching Results Cache results for performance-critical paths (e.g., service registration):
$classes = Cache::remember('namespace_classes', now()->addHours(1), function() {
return (new ClassFinder())->findClassesInNamespace('App\Services');
});
Combining with Reflection
Use ReflectionClass for deeper introspection:
$reflection = new ReflectionClass($class);
$methods = $reflection->getMethods();
Excluding Directories
Skip Tests, Migrations, or Vendor folders:
$finder = new ClassFinder();
$finder->excludeDirectories(['Tests', 'Migrations']);
$classes = $finder->findClassesInNamespace('App');
Leveraging with Laravel’s Facades
Integrate with app() for dependency injection:
$finder = app(ClassFinder::class);
Performance with Large Codebases
$finder->setMaxDepth(3); // Limit to 3 levels deep
False Positives in Trait/Interface Detection
findClassesByTrait may include classes that use the trait indirectly (e.g., via inheritance).class_uses() for stricter checks:
$classes = (new ClassFinder())->findClassesByTrait('Serializable');
$classes = array_filter($classes, fn($class) => in_array('Serializable', class_uses($class)));
Namespace Pollution
vendor/ or node_modules/.$finder->excludeDirectories(['vendor', 'node_modules']);
Static Analysis Limitations
eval() or create_function).Enable Verbose Output Temporarily enable debug mode to see scanned files:
$finder->setDebug(true);
$classes = $finder->findClassesInNamespace('App');
Validate Results
Cross-check with get_declared_classes() for edge cases:
$declared = get_declared_classes();
$found = (new ClassFinder())->findClassesInNamespace('App');
$missing = array_diff($declared, $found);
Handle Autoloading Issues If classes are missing, ensure Composer’s autoloader is up-to-date:
composer dump-autoload
Custom Filters Extend with anonymous functions or callables:
$finder = new ClassFinder();
$finder->addFilter(fn($class) => str_contains($class, 'Service'));
Post-Processing Hooks
Override ClassFinder::processClass() to modify results:
class CustomFinder extends ClassFinder {
protected function processClass(string $class): bool {
return parent::processClass($class) && !str_ends_with($class, 'Builder');
}
}
Integration with Laravel’s Events Trigger events when classes are discovered:
$finder = new ClassFinder();
$finder->on('class_found', fn($class) => Log::debug("Found: {$class}"));
$finder->findClassesInNamespace('App');
Parallel Processing For large scans, use Laravel’s queues or parallel processing:
$classes = (new ClassFinder())->findClassesInNamespace('App');
dispatch(fn() => processClasses($classes))->onQueue('class-discovery');
How can I help you explore Laravel packages today?