protected function scanClasses($dir, $depth = 2) {

        // Don't recurse if we've hit out depth limit
        if ($depth < 0) {
            return [];
        }

        $paths = scandir($dir);

        $classes = [];
        foreach ($paths as $path) {
            if (in_array($path, ['.','..'])) {
                continue;
            }

            $full = paths($dir,$path);

            if (is_dir($full)) {
                if ($depth > 0) {
                    $classes = array_merge($classes, $this->scanClasses($full, $depth-1));
                }
            } else {

                // Only scan PHP files
                if (fnmatch('*.php', $path)) {

                    $declarations = $this->scanFile($full);

                    // Iterate over all namespaces
                    foreach ($declarations as $namespaceRow) {
                        if (isset($namespaceRow['namespace']) && $namespaceRow) {
                            $namespace = rtrim($namespaceRow['namespace'], '\\').'\\';
                            $namespaceClasses = $namespaceRow['classes'];
                        } else {
                            $namespace = '';
                            $namespaceClasses = $namespaceRow;
                        }

                        // Iterate over all classes within NS
                        foreach ($namespaceClasses as $classRow) {
                            $className = $namespace.$classRow['name'];
                            $classes[strtolower($className)] = [$className, $full];

                            // Special case for main addon file
                            if ($classRow['type'] == 'CLASS') {
                                if (preg_match('`^[\w\d]+Addon$`', $classRow['name'])) {
                                    $this->special['addon'] = $className;
                                }
                            }
                        }
                    }
                }

            }
        }

        return $classes;
    }