As a developer, you may have faced the challenge of autoloading a variety of classes from multiple directories, where retrieving class information by reading a file in PHP is not enough. To address this issue, I developed ClassRetriever, a tool for retrieving class, interface, and trait information by filepath. ClassRetriever is part of midnite81/core
In a recent project, I needed to autoload namespaced classes from a dynamic set of directories and get the class name to instantiate the classes and run the process method on each class. For instance, suppose I have two classes called Hook1.php and Hook2.php in /var/www/html/app/Hooks, and two classes called Hook3.php and Hook4.php in /var/www/html/packages/Midnite81/Hooks/Hooks. The classes in the first directory have a different namespace than those in the second directory, so I cannot assume that they follow PSR-4 for autoloading the classes.
To auto-register the classes, I list the contents of each directory and pass each file to the ClassRetriever class, which provides me with the class name. Then, I can instantiate them and run the process method on each. Here's a simplified version of what I did:
protected function register(): void{ $classFiles = []; foreach ($this->autoRegisterPaths() as $path) { // use Laravel's filesystem to list all files $files = $this->files->allFiles($path); // loop over each file in the directory and add it to the array foreach ($files as $file) { $classFiles[] = $file; } } // turn the array into a collection using laravel's collect helper function // then map each item to the fully qualified name $this->classes = collect($classFiles)->map( fn (SplFileInfo $file) => ClassRetriever::fromSplFileInfo($file)->name );}
$this->classes
would contain an array of fully qualified class names, including App\Hook1
, App\Hook2
, Midnite81\Hooks\Hook3
, and Midnite81\Hooks\Hook4
.
Now that I have my array of classes, I can instantiate each of them and run the process method on each. Here's the code:
public function process(){ foreach ($this->classes as $class) { try { // using Laravel's app helper function to instantiate the class // though you could use $hook = new $class(); $hook = app($class); $hook->process(); } catch (Exception $e) { // do nothing } }}
It's worth noting that I did not check in this example if the method exists or if the classes implement a certain interface, but you may wish to do so.
The ClassRetriever tool gives you access to the fully qualified name, type, the class it extends (if it does), any interfaces implemented, any traits used, and if the class is abstract. You can find the full documentation here.
With autoloading capabilities, I can focus on writing the necessary classes without worrying about registering them. This is especially helpful when dealing with a large number of classes that need to be registered and are not all in the same place or namespace.