public static isSuperglobalVariableWithName ( string $name ) : boolean | ||
$name | string | |
return | boolean | True if the variable with the given name is a superglobal Implies Variable::isHardcodedGlobalVariableWithName($name) is true |
/** * Visit a node with kind `\ast\AST_VAR` * * @param Node $node * A node of the type indicated by the method name that we'd * like to figure out the type that it produces. * * @return UnionType * The set of types that are possibly produced by the * given node */ public function visitVar(Node $node) : UnionType { // $$var or ${...} (whose idea was that anyway?) if ($node->children['name'] instanceof Node && ($node->children['name']->kind == \ast\AST_VAR || $node->children['name']->kind == \ast\AST_BINARY_OP)) { return MixedType::instance()->asUnionType(); } // This is nonsense. Give up. if ($node->children['name'] instanceof Node) { return new UnionType(); } $variable_name = $node->children['name']; if (!$this->context->getScope()->hasVariableWithName($variable_name)) { if (!Variable::isSuperglobalVariableWithName($variable_name)) { Log::err(Log::EVAR, "Variable \${$variable_name} is not defined", $this->context->getFile(), $node->lineno ?? 0); } } else { $variable = $this->context->getScope()->getVariableWithName($variable_name); return $variable->getUnionType(); } return new UnionType(); }
/** * @param Node $node * A node to parse * * @return Context * A new or an unchanged context resulting from * parsing the node */ public function visitEncapsList(Node $node) : Context { foreach ((array) $node->children as $child_node) { // Confirm that variables exists if ($child_node instanceof Node && $child_node->kind == \ast\AST_VAR) { $variable_name = $child_node->children['name']; // Ignore $$var type things if (!is_string($variable_name)) { continue; } // Don't worry about non-existent undeclared variables // in the global scope if configured to do so if (Config::get()->ignore_undeclared_variables_in_global_scope && $this->context->isInGlobalScope()) { continue; } if (!$this->context->getScope()->hasVariableWithName($variable_name) && !Variable::isSuperglobalVariableWithName($variable_name)) { $this->emitIssue(Issue::UndeclaredVariable, $child_node->lineno ?? 0, $variable_name); } } } return $this->context; }
/** * Analyze an assignment where $variable_name is a superglobal, and return the new context. * May create a new variable in $this->context. * TODO: Emit issues if the assignment is incompatible with the pre-existing type? */ private function analyzeSuperglobalDim(Node $node, string $variable_name) : Context { $dim = $node->children['dim']; if ('GLOBALS' === $variable_name) { if (!is_string($dim)) { // You're not going to believe this, but I just // found a piece of code like $GLOBALS[mt_rand()]. // Super weird, right? return $this->context; } // assert(is_string($dim), "dim is not a string"); if (Variable::isSuperglobalVariableWithName($dim)) { // Don't override types of superglobals such as $_POST, $argv through $_GLOBALS['_POST'] = expr either. TODO: Warn. return $this->context; } $variable = new Variable($this->context, $dim, $this->right_type, $node->flags ?? 0); $this->context->addGlobalScopeVariable($variable); } // TODO: Assignment sanity checks. return $this->context; }
/** * Visit a node with kind `\ast\AST_VAR` * * @param Node $node * A node of the type indicated by the method name that we'd * like to figure out the type that it produces. * * @return UnionType * The set of types that are possibly produced by the * given node */ public function visitVar(Node $node) : UnionType { // $$var or ${...} (whose idea was that anyway?) if ($node->children['name'] instanceof Node && ($node->children['name']->kind == \ast\AST_VAR || $node->children['name']->kind == \ast\AST_BINARY_OP)) { return MixedType::instance()->asUnionType(); } // This is nonsense. Give up. if ($node->children['name'] instanceof Node) { return new UnionType(); } $variable_name = $node->children['name']; if (!$this->context->getScope()->hasVariableWithName($variable_name)) { if (!Variable::isSuperglobalVariableWithName($variable_name) && (!Config::get()->ignore_undeclared_variables_in_global_scope || !$this->context->isInGlobalScope())) { throw new IssueException(Issue::fromType(Issue::UndeclaredVariable)($this->context->getFile(), $node->lineno ?? 0, [$variable_name])); } } else { $variable = $this->context->getScope()->getVariableByName($variable_name); return $variable->getUnionType(); } return new UnionType(); }