PHP: How to get all classes when using autoloader

10,595

Solution 1

If you don't keep track of which classes exist, autoloading won't help you.

But the situation would be pretty much the same if you tried to include all files and see which classes would come out of it, when there would be a chance that you missed a file.

Whatever it is what you try to do: Try it differently. I highly doubt you have to instantiate ALL these classes when serving one single request. It would not be very beneficial to the performance if you had to scan ALL declared classes for an interface, and then create an instance for all of them.

Provide some kind of registering method to let the application know about your classes. If you really have to use them all, so be it. But scanning whatever code has been run previously does not sound right (and you didn't explain what you do at all).

Solution 2

You can use dirty hack and require_once all classes before get_declared_classes() function call.

  1. At first do dump all classes to class map via composer dumpautoload --optimize
  2. Now you can fetch composer loader and require all files
    $res = get_declared_classes();
    $autoloaderClassName = '';
    foreach ( $res as $className) {
        if (strpos($className, 'ComposerAutoloaderInit') === 0) {
            $autoloaderClassName = $className; // ComposerAutoloaderInit323a579f2019d15e328dd7fec58d8284 for me
            break;
        }
    }
    $classLoader = $autoloaderClassName::getLoader();
    foreach ($classLoader->getClassMap() as $path) {
        require_once $path;
    }
  1. Now you can easy use get_declared_classes() again, which return all classes the composer knowns

P.S. Don't use it in production.

Solution 3

I had similar use case for all *Sniff.php classes found in some directory.

You can use Nette\RobotLoader.

Snippets from my app for inspiration: RobotLoaderFactory + Getting all the classes

And for your use case:

$src = __DIR__ . '/src';

$robotLoader = new Nette\Loaders\RobotLoader\RobotLoader;
$robotLoader->setTempDirectory(__DIR__ . '/temp');
$robotLoader->addDirectory($src);
$robotLoader->acceptFiles = ['*Suffix.php']; // optional to reduce file count
$robotLoader->rebuild();

$foundClasses = array_keys($robotLoader->getIndexedClasses());

// filter in any way
Share:
10,595
SiliconMind
Author by

SiliconMind

Updated on June 24, 2022

Comments

  • SiliconMind
    SiliconMind almost 2 years

    I'm using composer to generate autoloader:

    "autoload": {
      "psr-4": {
        "SomeNamespace\\": "src/SomeDir"
      }
    }
    

    I need to create instances of all classes that implement specific interface. It's fairly easy when not using autoloader, however get_declared_classes() is not playing well with autoloaders. It will list a class only after it was instantiated with autoloader.

  • SiliconMind
    SiliconMind about 8 years
    You are right. I didn't make myself clear when writing that I need to instantiate all these classes. The ultimate goal is to instantiate only the ones needed for a request and you pointed me into the right direction. I guess a service container would be the best option here. I thought I could avoid it as it's very small app, but I guess I don't have much choice :)
  • Christian
    Christian almost 5 years
    The first few lines can be skipped - requiring vendor/autoload.php returns the autoloader (eg, $classLoader = require('vendor/autoload.php');)