Phan\Analysis\AssignmentVisitor::visitProp PHP Method

visitProp() public method

public visitProp ( 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 visitProp(Node $node) : Context
    {
        $property_name = $node->children['prop'];
        // Things like $foo->$bar
        if (!is_string($property_name)) {
            return $this->context;
        }
        assert(is_string($property_name), "Property must be string");
        try {
            $class_list = (new ContextNode($this->code_base, $this->context, $node->children['expr']))->getClassList();
        } catch (CodeBaseException $exception) {
            // This really shouldn't happen since the code
            // parsed cleanly. This should fatal.
            // throw $exception;
            return $this->context;
        } catch (\Exception $exception) {
            // If we can't figure out what kind of a class
            // this is, don't worry about it
            return $this->context;
        }
        foreach ($class_list as $clazz) {
            // Check to see if this class has the property or
            // a setter
            if (!$clazz->hasPropertyWithName($this->code_base, $property_name)) {
                if (!$clazz->hasMethodWithName($this->code_base, '__set')) {
                    continue;
                }
            }
            try {
                $property = $clazz->getPropertyByNameInContext($this->code_base, $property_name, $this->context);
            } catch (IssueException $exception) {
                Issue::maybeEmitInstance($this->code_base, $this->context, $exception->getIssueInstance());
                return $this->context;
            }
            if (!$this->right_type->canCastToExpandedUnionType($property->getUnionType(), $this->code_base)) {
                $this->emitIssue(Issue::TypeMismatchProperty, $node->lineno ?? 0, (string) $this->right_type, "{$clazz->getFQSEN()}::{$property->getName()}", (string) $property->getUnionType());
                return $this->context;
            } else {
                // If we're assigning to an array element then we don't
                // know what the constitutation of the parameter is
                // outside of the scope of this assignment, so we add to
                // its union type rather than replace it.
                if ($this->is_dim_assignment) {
                    $property->getUnionType()->addUnionType($this->right_type);
                }
            }
            // After having checked it, add this type to it
            $property->getUnionType()->addUnionType($this->right_type);
            return $this->context;
        }
        $std_class_fqsen = FullyQualifiedClassName::getStdClassFQSEN();
        if (Config::get()->allow_missing_properties || !empty($class_list) && $class_list[0]->getFQSEN() == $std_class_fqsen) {
            try {
                // Create the property
                $property = (new ContextNode($this->code_base, $this->context, $node))->getOrCreateProperty($property_name);
                $property->getUnionType()->addUnionType($this->right_type);
            } catch (\Exception $exception) {
                // swallow it
            }
        } elseif (!empty($class_list)) {
            $this->emitIssue(Issue::UndeclaredProperty, $node->lineno ?? 0, "{$class_list[0]->getFQSEN()}->{$property_name}");
        } else {
            // If we hit this part, we couldn't figure out
            // the class, so we ignore the issue
        }
        return $this->context;
    }