How to get all class names inside a particular namespace?

I want to get all classes inside a namespace. I have something like this:

#File: MyClass1.php
namespace MyNamespace;

class MyClass1() { ... }

#File: MyClass2.php
namespace MyNamespace;

class MyClass2() { ... }

#Any number of files and classes with MyNamespace may be specified.

#File: ClassHandler.php
namespace SomethingElse;
use MyNamespace as Classes;

class ClassHandler {
    public function getAllClasses() {
        // Here I want every classes declared inside MyNamespace.
    }
}

I tried get_declared_classes() inside getAllClasses() but MyClass1 and MyClass2 were not in the list.

How could I do that?


The generic approach would be to get all fully qualified classnames (class with full namespace) in your project, and then filter by the wanted namespace.

PHP offers some native functions to get those classes (get_declared_classes, etc), but they won't be able to find classes that have not been loaded (include / require), therefore it won't work as expected with autoloaders (like Composer for example). This is a major issue as the usage of autoloaders is very common.

So your last resort is to find all PHP files by yourself and parse them to extract their namespace and class:

$path = __DIR__;
$fqcns = array();

$allFiles = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path));
$phpFiles = new RegexIterator($allFiles, '/\.php$/');
foreach ($phpFiles as $phpFile) {
    $content = file_get_contents($phpFile->getRealPath());
    $tokens = token_get_all($content);
    $namespace = '';
    for ($index = 0; isset($tokens[$index]); $index++) {
        if (!isset($tokens[$index][0])) {
            continue;
        }
        if (T_NAMESPACE === $tokens[$index][0]) {
            $index += 2; // Skip namespace keyword and whitespace
            while (isset($tokens[$index]) && is_array($tokens[$index])) {
                $namespace .= $tokens[$index++][1];
            }
        }
        if (T_CLASS === $tokens[$index][0] && T_WHITESPACE === $tokens[$index + 1][0] && T_STRING === $tokens[$index + 2][0]) {
            $index += 2; // Skip class keyword and whitespace
            $fqcns[] = $namespace.'\\'.$tokens[$index][1];

            # break if you have one class per file (psr-4 compliant)
            # otherwise you'll need to handle class constants (Foo::class)
            break;
        }
    }
}

If you follow PSR 0 or PSR 4 standards (your directory tree reflects your namespace), you don't have to filter anything: just give the path that corresponds to the namespace you want.

If you're not a fan of copying/pasting the above code snippets, you can simply install this library: https://github.com/gnugat/nomo-spaco . If you use PHP >= 5.5, you can also use the following library: https://github.com/hanneskod/classtools .


Update: Since this answer became somewhat popular, I've created a packagist package to simplify things. It contains basically what I've described here, without the need to add the class yourself or configure the $appRoot manually. It may eventually support more than just PSR-4.

That package can be found here: haydenpierce/class-finder.

$ composer require haydenpierce/class-finder

See more info in the README file.


I wasn't happy with any of the solutions here so I ended up building my class to handle this. This solution requires that you are:

  • Using Composer
  • Using PSR-4

In a nutshell, this class attempts to figure out where the classes actually live on your filesystem based on the namespaces you've defined in composer.json. For instance, classes defined in the namespace Backup\Test are found in /home/hpierce/BackupApplicationRoot/src/Test. This can be trusted because mapping a directory structure to namespace is required by PSR-4:

The contiguous sub-namespace names after the "namespace prefix" correspond to a subdirectory within a "base directory", in which the namespace separators represent directory separators. The subdirectory name MUST match the case of the sub-namespace names.

You may need to adjust appRoot to point to the directory that contains composer.json.

<?php    
namespace Backup\Util;

class ClassFinder
{
    //This value should be the directory that contains composer.json
    const appRoot = __DIR__ . "/../../";

    public static function getClassesInNamespace($namespace)
    {
        $files = scandir(self::getNamespaceDirectory($namespace));

        $classes = array_map(function($file) use ($namespace){
            return $namespace . '\\' . str_replace('.php', '', $file);
        }, $files);

        return array_filter($classes, function($possibleClass){
            return class_exists($possibleClass);
        });
    }

    private static function getDefinedNamespaces()
    {
        $composerJsonPath = self::appRoot . 'composer.json';
        $composerConfig = json_decode(file_get_contents($composerJsonPath));

        return (array) $composerConfig->autoload->{'psr-4'};
    }

    private static function getNamespaceDirectory($namespace)
    {
        $composerNamespaces = self::getDefinedNamespaces();

        $namespaceFragments = explode('\\', $namespace);
        $undefinedNamespaceFragments = [];

        while($namespaceFragments) {
            $possibleNamespace = implode('\\', $namespaceFragments) . '\\';

            if(array_key_exists($possibleNamespace, $composerNamespaces)){
                return realpath(self::appRoot . $composerNamespaces[$possibleNamespace] . implode('/', $undefinedNamespaceFragments));
            }

            array_unshift($undefinedNamespaceFragments, array_pop($namespaceFragments));            
        }

        return false;
    }
}