Phan\Parse\ParseVisitor::visitClass PHP Method

visitClass() public method

Visit a node with kind \ast\AST_CLASS
public visitClass ( ast\Node\Decl $node ) : Context
$node ast\Node\Decl A node to parse
return Phan\Language\Context A new or an unchanged context resulting from parsing the node
    public function visitClass(Decl $node) : Context
    {
        if ($node->flags & \ast\flags\CLASS_ANONYMOUS) {
            $class_name = (new ContextNode($this->code_base, $this->context, $node))->getUnqualifiedNameForAnonymousClass();
        } else {
            $class_name = (string) $node->name;
        }
        // This happens now and then and I have no idea
        // why.
        if (empty($class_name)) {
            return $this->context;
        }
        assert(!empty($class_name), "Class must have name in {$this->context}");
        $class_fqsen = FullyQualifiedClassName::fromStringInContext($class_name, $this->context);
        assert($class_fqsen instanceof FullyQualifiedClassName, "The class FQSEN must be a FullyQualifiedClassName");
        // Hunt for an available alternate ID if necessary
        $alternate_id = 0;
        while ($this->code_base->hasClassWithFQSEN($class_fqsen)) {
            $class_fqsen = $class_fqsen->withAlternateId(++$alternate_id);
        }
        // Build the class from what we know so far
        $class_context = $this->context->withLineNumberStart($node->lineno ?? 0)->withLineNumberEnd($node->endLineno ?? -1);
        $class = new Clazz($class_context, $class_name, $class_fqsen->asUnionType(), $node->flags ?? 0, $class_fqsen);
        // Set the scope of the class's context to be the
        // internal scope of the class
        $class_context = $class_context->withScope($class->getInternalScope());
        // Get a comment on the class declaration
        $comment = Comment::fromStringInContext($node->docComment ?? '', $this->context);
        // Add any template types parameterizing a generic class
        foreach ($comment->getTemplateTypeList() as $template_type) {
            $class->getInternalScope()->addTemplateType($template_type);
        }
        $class->setIsDeprecated($comment->isDeprecated());
        $class->setSuppressIssueList($comment->getSuppressIssueList());
        // Add the class to the code base as a globally
        // accessible object
        $this->code_base->addClass($class);
        // Look to see if we have a parent class
        if (!empty($node->children['extends'])) {
            $parent_class_name = $node->children['extends']->children['name'];
            // Check to see if the name isn't fully qualified
            if ($node->children['extends']->flags & \ast\flags\NAME_NOT_FQ) {
                if ($this->context->hasNamespaceMapFor(\ast\flags\USE_NORMAL, $parent_class_name)) {
                    // Get a fully-qualified name
                    $parent_class_name = (string) $this->context->getNamespaceMapFor(\ast\flags\USE_NORMAL, $parent_class_name);
                } else {
                    $parent_class_name = $this->context->getNamespace() . '\\' . $parent_class_name;
                }
            }
            // The name is fully qualified. Make sure it looks
            // like it is
            if (0 !== strpos($parent_class_name, '\\')) {
                $parent_class_name = '\\' . $parent_class_name;
            }
            $parent_fqsen = FullyQualifiedClassName::fromStringInContext($parent_class_name, $this->context);
            // Set the parent for the class
            $class->setParentType($parent_fqsen->asType());
        }
        // If the class explicitly sets its overriding extension type,
        // set that on the class
        $inherited_type_option = $comment->getInheritedTypeOption();
        if ($inherited_type_option->isDefined()) {
            $class->setParentType($inherited_type_option->get());
        }
        // Add any implemeneted interfaces
        if (!empty($node->children['implements'])) {
            $interface_list = (new ContextNode($this->code_base, $this->context, $node->children['implements']))->getQualifiedNameList();
            foreach ($interface_list as $name) {
                $class->addInterfaceClassFQSEN(FullyQualifiedClassName::fromFullyQualifiedString($name));
            }
        }
        return $class_context;
    }