use Mfn\PHP\Analyzer\Analyzers\ObjectGraph\ObjectGraph; use Mfn\PHP\Analyzer\Analyzers\Parser; use Mfn\PHP\Analyzer\Logger\Stdout; use Mfn\PHP\Analyzer\Project; use Mfn\PHP\Analyzer\Util\Util; use PhpParser\Lexer; require_once __DIR__ . '/../vendor/autoload.php'; error_reporting(E_ALL); Util::installMinimalError2ExceptionHandler(); $projectRealPath = realpath(__DIR__ . DIRECTORY_SEPARATOR . '..'); # Use analyzer to gather the object graph $project = new Project(new Stdout()); $project->addSplFileInfos(Util::scanDir(__DIR__ . '/../lib/')); $project->addAnalyzers([new Parser(new \PhpParser\Parser(new Lexer())), new NameResolver(), $objectGraph = new ObjectGraph()]); $project->analyze(); $helper = new Helper($objectGraph); $className = 'Mfn\\PHP\\Analyzer\\Analyzers\\Analyzer'; $class = $objectGraph->getClassByFqn($className); if (NULL === $class) { throw new \RuntimeException("Unable to find class {$className}"); } unset($className); $descendants = $helper->findExtends($class, true); sort($descendants); /** @var string[] $index */ $index = []; $index[] = '# Built-in / available Analyzers'; $index[] = ''; foreach ($descendants as $class) { $doccomment = $class->getClass()->getDocComment(); if (NULL === $doccomment) {
/** * Recursively searches "down" the object graph to find classes, or classes * extended interfaces implementing this interface, which should implement * this method. * * Abstract classes are, like interfaces, "skipped" and their children are * scanned. * * @param ParsedMethod $interfaceMethod * @param ParsedInterface[]|ParsedClass[] $implementors * @return ParsedClass[] */ private function findSubtypeUntilMethodMatchesRecursive(ParsedMethod $interfaceMethod, $implementors) { $classesMissingMethod = []; foreach ($implementors as $object) { # interfaces only delegate down to their implementors if ($object instanceof ParsedInterface) { $classesMissingMethod = array_merge($classesMissingMethod, $this->findSubtypeUntilMethodMatchesRecursive($interfaceMethod, $this->helper->findImplements($object))); continue; } else { if ($object instanceof ParsedClass) { $methodName = $interfaceMethod->getNormalizedName(); # check if any parent implements the interface method if (Helper::classImplements($object->getParent(), $interfaceMethod->getInterface()) || self::classHasParentMethod($object->getParent(), $methodName)) { continue; } $foundMethod = false; foreach ($object->getMethods() as $method) { if ($methodName === $method->getNormalizedName()) { $foundMethod = true; break; } } # abstract classes must not implement it ... if ($object->getClass()->isAbstract()) { if (!$foundMethod) { # ... but we search further down the inheritance tree $classesMissingMethod = array_merge($classesMissingMethod, $this->findSubtypeUntilMethodMatchesRecursive($interfaceMethod, $this->helper->findExtends($object))); } continue; } if (!$foundMethod) { $classesMissingMethod[] = $object; } } } } return $classesMissingMethod; }