skip to Main Content

I’m working on a code generator, and would like to get the path to a namespace.

That is, given namespace ‘AppController’, I’d like to get "src/Controller".

I see how to get that information using ReflectionClass if I already had the class, but in this case I don’t have it yet.

My solution at the application level is to simply read composer.json and look for the autload section. But that won’t work with bundles (e.g. namespace AcmeApiBundle -> vendor/acme/api-bundle’). I imagine there’s an autoload map somewhere, but I can’t find how to access it.

FWIW, I’m using Symfony, but I don’t think that’s going to matter here. More importantly, I’m using composer and psr-4 autloaded namespaces/classes.

Thanks.

2

Answers


  1. Chosen as BEST ANSWER

    In the end, the mapping file I was looking for is found in vendor/composer/autoload_psr4.php, and I was able to do the mapping by reading it and traversing the map.

        public static function namespaceToPath(string $namespace): ?string
        {
            $x = include "vendor/composer/autoload_psr4.php";
            $result = null;
            $parts = explode('\', $namespace);
            $paths = [];
            do {
                $namespace = join('\', $parts);
                $query = $namespace . '\';
                if (array_key_exists($query, $x)) {
                    array_unshift($paths, $x[$query][0]);
                    return join('/', $paths);
                } else {
                    array_unshift($paths, array_pop($parts));
                }
            } while (!$result && count($parts));
            return null;
        }
    

  2. The "path to a namespace" does not necessarily exist as the mapping between class name, namespace and all, can point literally anywhere. Only in the specific case of a PSR4-compliant autoloader does a namespace have any significance in that the there is a "root" directory that represents an arbitrary prefix of the namespace, and subdirectories/files representative of the rest of the class name. Any other type of autoloader [eg: classmap] will not necessarily have any relation between class name and file path.

    Further to that, even in the case of a PSR4-compliant autoloader the specific function of a given autoloader may well prevent any dynamically-generated code from being picked up, eg: calling composer with -o / --optimize-autloader will cause Composer to scan its autoload directories for classes and generate a static classmap, so anything that you were to add there would not be picked up until you re-generated the classmap and restarted execution. While not the default, -o is a strongly-recommended and widely-used optimization.

    A better solution would be to define your own custom autoloader and use spl_autoload_register() to append it to the autoloader queue after the composer autoloader. If you want your class to override something coming from composer you would want to use the $prepend argument.

    Other related caveats:

    • Once a class is loaded it can never be un-loaded or re-loaded.
    • Modifying anything within the vendor/ directory is a generally not a good idea as that directory should be considered ephemeral and composer operations can and will erase any changes.
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search