Phan\Analysis\PostOrderAnalysisVisitor::visitCall PHP Method

visitCall() public method

public visitCall ( ast\Node $node ) : Context
$node ast\Node A node to parse
return Phan\Language\Context A new or an unchanged context resulting from parsing the node
    public function visitCall(Node $node) : Context
    {
        $expression = $node->children['expr'];
        (new ContextNode($this->code_base, $this->context, $node))->analyzeBackwardCompatibility();
        foreach ($node->children['args']->children ?? [] as $arg_node) {
            if ($arg_node instanceof Node) {
                (new ContextNode($this->code_base, $this->context, $arg_node))->analyzeBackwardCompatibility();
            }
        }
        if ($expression->kind == \ast\AST_VAR) {
            $variable_name = (new ContextNode($this->code_base, $this->context, $expression))->getVariableName();
            if (empty($variable_name)) {
                return $this->context;
            }
            // $var() - hopefully a closure, otherwise we don't know
            if ($this->context->getScope()->hasVariableWithName($variable_name)) {
                $variable = $this->context->getScope()->getVariableByName($variable_name);
                $union_type = $variable->getUnionType();
                if ($union_type->isEmpty()) {
                    return $this->context;
                }
                foreach ($union_type->getTypeSet() as $type) {
                    if (!$type instanceof CallableType) {
                        continue;
                    }
                    $closure_fqsen = FullyQualifiedFunctionName::fromFullyQualifiedString((string) $type->asFQSEN());
                    if ($this->code_base->hasFunctionWithFQSEN($closure_fqsen)) {
                        // Get the closure
                        $function = $this->code_base->getFunctionByFQSEN($closure_fqsen);
                        // Check the call for paraemter and argument types
                        $this->analyzeCallToMethod($this->code_base, $function, $node);
                    }
                }
            }
        } elseif ($expression->kind == \ast\AST_NAME) {
            try {
                $method = (new ContextNode($this->code_base, $this->context, $expression))->getFunction($expression->children['name'] ?? $expression->children['method']);
            } catch (IssueException $exception) {
                Issue::maybeEmitInstance($this->code_base, $this->context, $exception->getIssueInstance());
                return $this->context;
            }
            // Check the call for paraemter and argument types
            $this->analyzeCallToMethod($this->code_base, $method, $node);
        } elseif ($expression->kind == \ast\AST_CALL || $expression->kind == \ast\AST_STATIC_CALL || $expression->kind == \ast\AST_NEW || $expression->kind == \ast\AST_METHOD_CALL) {
            $class_list = (new ContextNode($this->code_base, $this->context, $expression))->getClassList();
            foreach ($class_list as $class) {
                if (!$class->hasMethodWithName($this->code_base, '__invoke')) {
                    continue;
                }
                $method = $class->getMethodByNameInContext($this->code_base, '__invoke', $this->context);
                // Check the call for paraemter and argument types
                $this->analyzeCallToMethod($this->code_base, $method, $node);
            }
        }
        return $this->context;
    }