本文整理汇总了PHP中Phan\Language\Context::getScope方法的典型用法代码示例。如果您正苦于以下问题:PHP Context::getScope方法的具体用法?PHP Context::getScope怎么用?PHP Context::getScope使用的例子?那么, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类Phan\Language\Context
的用法示例。
在下文中一共展示了Context::getScope方法的13个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的PHP代码示例。
示例1: visitVar
/**
* @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 string
* The class name represented by the given call
*/
public function visitVar(Node $node) : string
{
// $$var->method()
if ($node->children['name'] instanceof Node) {
return '';
}
// $this->method()
if ($node->children['name'] == 'this') {
if (!$this->context->isInClassScope()) {
Log::err(Log::ESTATIC, 'Using $this when not in object context', $this->context->getFile(), $node->lineno);
return '';
}
return (string) $this->context->getClassFQSEN();
}
$variable_name = $node->children['name'];
if (!$this->context->getScope()->hasVariableWithName($variable_name)) {
// Got lost, couldn't find the variable in the current scope
// If it really isn't defined, it will be caught by the
// undefined var error
return '';
}
$variable = $this->context->getScope()->getVariableWithName($variable_name);
// Hack - loop through the possible types of the var and assume
// first found class is correct
foreach ($variable->getUnionType()->nonGenericArrayTypes()->getTypeList() as $type) {
$child_class_fqsen = FullyQualifiedClassName::fromStringInContext((string) $type, $this->context);
if ($this->code_base->hasClassWithFQSEN($child_class_fqsen)) {
return (string) FullyQualifiedClassName::fromStringInContext((string) $type, $this->context);
}
}
// We land here if we have a variable
// with a native type or no known type.
return '';
}
示例2: visitCall
/**
* @param Node $node
* A node to parse
*
* @return 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()->getVariableWithName($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->hasMethod($closure_fqsen)) {
// Get the closure
$method = $this->code_base->getMethod($closure_fqsen);
// Check the call for paraemter and argument types
$this->analyzeCallToMethod($this->code_base, $method, $node);
}
}
}
} else {
if ($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) {
$exception->getIssueInstance()();
return $this->context;
}
// Check the call for paraemter and argument types
$this->analyzeCallToMethod($this->code_base, $method, $node);
} else {
if ($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;
}
示例3: visitVar
/**
* @param Node $node
* A node to parse
*
* @return Context
* A new or an unchanged context resulting from
* parsing the node
*/
public function visitVar(Node $node) : Context
{
$variable_name = AST::variableName($node);
// Check to see if the variable already exists
if ($this->context->getScope()->hasVariableWithName($variable_name)) {
$variable = $this->context->getScope()->getVariableWithName($variable_name);
// 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) {
$variable->getUnionType()->addUnionType($this->right_type);
} else {
// If the variable isn't a pass-by-reference paramter
// we clone it so as to not disturb its previous types
// as we replace it.
if (!($variable instanceof Parameter && $variable->isPassByReference())) {
$variable = clone $variable;
}
$variable->setUnionType($this->right_type);
}
$this->context->addScopeVariable($variable);
return $this->context;
}
$variable = Variable::fromNodeInContext($this->assignment_node, $this->context, $this->code_base);
// Set that type on the variable
$variable->getUnionType()->addUnionType($this->right_type);
// Note that we're not creating a new scope, just
// adding variables to the existing scope
$this->context->addScopeVariable($variable);
return $this->context;
}
示例4: getVariable
/**
* @return Variable
* A variable in scope or a new variable
*
* @throws NodeException
* An exception is thrown if we can't understand the node
*
* @throws IssueException
* A IssueException is thrown if the variable doesn't
* exist
*/
public function getVariable() : Variable
{
// Get the name of the variable
$variable_name = $this->getVariableName();
if (empty($variable_name)) {
throw new NodeException($this->node, "Variable name not found");
}
// Check to see if the variable exists in this scope
if (!$this->context->getScope()->hasVariableWithName($variable_name)) {
throw new IssueException(Issue::fromType(Issue::UndeclaredVariable)($this->context->getFile(), $this->node->lineno ?? 0, [$variable_name]));
}
return $this->context->getScope()->getVariableWithName($variable_name);
}
示例5: getVariable
/**
* @return Variable
* A variable in scope or a new variable
*
* @throws NodeException
* An exception is thrown if we can't understand the node
*
* @throws CodeBaseException
* A CodeBaseException is thrown if the variable doesn't
* exist
*/
public function getVariable() : Variable
{
// Get the name of the variable
$variable_name = $this->getVariableName();
if (empty($variable_name)) {
throw new NodeException($this->node, "Variable name not found");
}
// Check to see if the variable exists in this scope
if (!$this->context->getScope()->hasVariableWithName($variable_name)) {
throw new CodeBaseException(null, "Variable with name {$variable_name} doesn't exist in {$this->context}");
}
return $this->context->getScope()->getVariableWithName($variable_name);
}
示例6: visitCall
/**
* @param Node $node
* A node to parse
*
* @return Context
* A new or an unchanged context resulting from
* parsing the node
*/
public function visitCall(Node $node) : Context
{
$expression = $node->children['expr'];
if (Config::get()->backward_compatibility_checks) {
AST::backwardCompatibilityCheck($this->context, $node);
foreach ($node->children['args']->children as $arg_node) {
if ($arg_node instanceof Node) {
AST::backwardCompatibilityCheck($this->context, $arg_node);
}
}
}
if ($expression->kind == \ast\AST_NAME) {
try {
$method = AST::functionFromNameInContext($expression->children['name'], $this->context, $this->code_base);
} catch (CodeBaseException $exception) {
Log::err(Log::EUNDEF, $exception->getMessage(), $this->context->getFile(), $node->lineno);
return $this->context;
}
// Check the call for paraemter and argument types
$this->analyzeCallToMethod($this->code_base, $method, $node);
} else {
if ($expression->kind == \ast\AST_VAR) {
$variable_name = AST::variableName($expression);
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()->getVariableWithName($variable_name);
$union_type = $variable->getUnionType();
if ($union_type->isEmpty()) {
return $this->context;
}
$type = $union_type->head();
if (!$type instanceof CallableType) {
return $this->context;
}
$closure_fqsen = FullyQualifiedFunctionName::fromFullyQualifiedString((string) $type->asFQSEN());
if ($this->code_base->hasMethod($closure_fqsen)) {
// Get the closure
$method = $this->code_base->getMethod($closure_fqsen);
// Check the call for paraemter and argument types
$this->analyzeCallToMethod($this->code_base, $method, $node);
}
}
}
}
return $this->context;
}
示例7: visitVar
/**
* @param Node $node
* A node to parse
*
* @return Context
* A new or an unchanged context resulting from
* parsing the node
*/
public function visitVar(Node $node) : Context
{
$variable_name = AST::variableName($node);
// Check to see if the variable already exists
if ($this->context->getScope()->hasVariableWithName($variable_name)) {
$variable = $this->context->getScope()->getVariableWithName($variable_name);
$variable->setUnionType($this->right_type);
$this->context->addScopeVariable($variable);
return $this->context;
}
$variable = Variable::fromNodeInContext($this->assignment_node, $this->context, $this->code_base);
// Set that type on the variable
$variable->getUnionType()->addUnionType($this->right_type);
// Note that we're not creating a new scope, just
// adding variables to the existing scope
$this->context->addScopeVariable($variable);
return $this->context;
}
示例8: visitVar
/**
* @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 string
* The class name represented by the given call
*/
public function visitVar(Node $node) : string
{
// $$var->method()
if ($node->children['name'] instanceof Node) {
return '';
}
// $this->method()
if ($node->children['name'] == 'this') {
if (!$this->context->isInClassScope()) {
Log::err(Log::ESTATIC, 'Using $this when not in object context', $this->context->getFile(), $node->lineno);
return '';
}
return (string) $this->context->getClassFQSEN();
}
$variable_name = $node->children['name'];
if (!$this->context->getScope()->hasVariableWithName($variable_name)) {
// Got lost, couldn't find the variable in the current scope
// If it really isn't defined, it will be caught by the
// undefined var error
return '';
}
$variable = $this->context->getScope()->getVariableWithName($variable_name);
$union_type = $variable->getUnionType()->nonNativeTypes()->nonGenericArrayTypes();
// If there are no candidate classes, we'll emit whatever
// we have so that we can differentiate between
// no-known-type and a shitty type
if ($union_type->isEmpty()) {
if (!$variable->getUnionType()->isEmpty() && !$variable->getUnionType()->hasType(MixedType::instance()) && !$variable->getUnionType()->hasType(ArrayType::instance()) && !$variable->getUnionType()->hasType(ObjectType::instance())) {
$type = (string) $variable->getUnionType();
throw new TypeException("Calling method on non-class type {$type}");
}
// No viable class types for the variable.
return '';
}
$class_fqsen = $this->chooseSingleFQSEN(array_map(function (Type $type) {
return $type->asFQSEN();
}, $union_type->getTypeList()));
if ($this->code_base->hasClassWithFQSEN($class_fqsen)) {
return (string) $class_fqsen;
}
// We couldn't find any viable classes
return '';
}
示例9: visitVar
/**
* 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();
}
示例10: visitIf
/**
* @param Node $node
* A node to parse
*
* @return Context
* A new or an unchanged context resulting from
* parsing the node
*/
public function visitIf(Node $node) : Context
{
// Get the list of scopes for each branch of the
// conditional
$scope_list = array_map(function (Context $context) {
return $context->getScope();
}, $this->child_context_list);
$has_else = array_reduce($node->children ?? [], function (bool $carry, $child_node) {
return $carry || $child_node instanceof Node && empty($child_node->children['cond']);
}, false);
// If we're not guaranteed to hit at least one
// branch, mark the incoming scope as a possibility
if (!$has_else) {
$scope_list[] = $this->context->getScope();
}
// If there weren't multiple branches, continue on
// as if the conditional never happened
if (count($scope_list) < 2) {
return array_values($this->child_context_list)[0];
}
// Get a list of all variables in all scopes
$variable_map = [];
foreach ($scope_list as $scope) {
foreach ($scope->getVariableMap() as $name => $variable) {
$variable_map[$name] = $variable;
}
}
// A function that determins if a variable is defined on
// every branch
$is_defined_on_all_branches = function (string $variable_name) use($scope_list) {
return array_reduce($scope_list, function (bool $has_variable, Scope $scope) use($variable_name) {
return $has_variable && $scope->hasVariableWithName($variable_name);
}, true);
};
// Get the intersection of all types for all versions of
// the variable from every side of the branch
$common_union_type = function (string $variable_name) use($scope_list) {
// Get a list of all variables with the given name from
// each scope
$variable_list = array_filter(array_map(function (Scope $scope) use($variable_name) {
if (!$scope->hasVariableWithName($variable_name)) {
return null;
}
return $scope->getVariableWithName($variable_name);
}, $scope_list));
// Get the list of types for each version of the variable
$type_set_list = array_map(function (Variable $variable) : Set {
return $variable->getUnionType()->getTypeSet();
}, $variable_list);
if (count($type_set_list) < 2) {
return new UnionType($type_set_list[0] ?? []);
}
return new UnionType(Set::intersectAll($type_set_list));
};
$scope = new Scope();
foreach ($variable_map as $name => $variable) {
// Skip variables that are only partially defined
if (!$is_defined_on_all_branches($name)) {
continue;
}
// Limit the type of the variable to the subset
// of types that are common to all branches
$variable = clone $variable;
$variable->setUnionType($common_union_type($name));
// Add the variable to the outgoing scope
$scope->addVariable($variable);
}
// print '<'.implode("\t", $scope_list) . "\n";
// print '>'.$scope."\n";
// Set the new scope with only the variables and types
// that are common to all branches
return $this->context->withScope($scope);
}
示例11: getOrCreateVariableFromNodeInContext
/**
* @param Node $node
* A node that has a reference to a variable
*
* @param Context $context
* The context in which we found the reference
*
* @param CodeBase $code_base
*
* @return Variable
* A variable in scope or a new variable
*
* @throws NodeException
* An exception is thrown if we can't understand the node
*/
public static function getOrCreateVariableFromNodeInContext(Node $node, Context $context, CodeBase $code_base) : Variable
{
// Get the name of the variable
$variable_name = self::variableName($node);
if (empty($variable_name)) {
throw new NodeException($node, "Variable name not found");
}
// Check to see if the variable exists in this scope
if ($context->getScope()->hasVariableWithName($variable_name)) {
return $context->getScope()->getVariableWithName($variable_name);
}
// Create a new variable
$variable = Variable::fromNodeInContext($node, $context, $code_base, false);
$context->addScopeVariable($variable);
return $variable;
}
示例12: visitMethodCall
/**
* @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 string
* The class name represented by the given call
*/
public function visitMethodCall(Node $node) : string
{
if ($node->children['expr']->kind == \ast\AST_VAR) {
if ($node->children['expr']->children['name'] instanceof Node) {
return '';
}
// $var->method()
if ($node->children['expr']->children['name'] == 'this') {
if (!$this->context->isInClassScope()) {
Log::err(Log::ESTATIC, 'Using $this when not in object context', $this->context->getFile(), $node->lineno);
return '';
}
return (string) $this->context->getClassFQSEN();
}
$variable_name = $node->children['expr']->children['name'];
if (!$this->context->getScope()->hasVariableWithName($variable_name)) {
// Got lost, couldn't find the variable in the current scope
// If it really isn't defined, it will be caught by the
// undefined var error
return '';
}
$variable = $this->context->getScope()->getVariableWithName($variable_name);
// Hack - loop through the possible types of the var and assume
// first found class is correct
foreach ($variable->getUnionType()->nonGenericArrayTypes()->getTypeList() as $type) {
$child_class_fqsen = FullyQualifiedClassName::fromStringInContext((string) $type, $this->context);
if ($this->code_base->hasClassWithFQSEN($child_class_fqsen)) {
return (string) FullyQualifiedClassName::fromStringInContext((string) $type, $this->context);
}
}
// Could not find name
return '';
}
if ($node->children['expr']->kind == \ast\AST_PROP) {
$prop = $node->children['expr'];
if (!($prop->children['expr']->kind == \ast\AST_VAR && !$prop->children['expr']->children['name'] instanceof Node)) {
return '';
}
// $var->prop->method()
$var = $prop->children['expr'];
if ($var->children['name'] == 'this') {
// If we're not in a class scope, 'this' won't work
if (!$this->context->isInClassScope()) {
Log::err(Log::ESTATIC, 'Using $this when not in object context', $this->context->getFile(), $node->lineno);
return '';
}
// Get the class in scope
$clazz = $this->code_base->getClassByFQSEN($this->context->getClassFQSEN());
if ($prop->children['prop'] instanceof Node) {
// $this->$prop->method() - too dynamic, give up
return '';
}
$property_name = $prop->children['prop'];
if ($clazz->hasPropertyWithName($this->code_base, $property_name)) {
try {
$property = $clazz->getPropertyByNameInContext($this->code_base, $property_name, $this->context);
} catch (AccessException $exception) {
Log::err(Log::EACCESS, $exception->getMessage(), $this->context->getFile(), $node->lineno);
return '';
}
// Find the first viable property type
foreach ($property->getUnionType()->nonGenericArrayTypes()->getTypeList() as $type) {
$class_fqsen = FullyQualifiedClassName::fromStringInContext((string) $type, $this->context);
if ($this->code_base->hasClassWithFQSEN($class_fqsen)) {
return (string) $class_fqsen;
}
}
}
// No such property was found, or none were classes
// that could be found
return '';
}
return '';
}
if ($node->children['expr']->kind == \ast\AST_METHOD_CALL) {
// Get the type returned by the first method
// call.
$union_type = UnionType::fromNode($this->context, $this->code_base, $node->children['expr']);
// Find the subset of types that are viable
// classes
$viable_class_types = $union_type->nonNativeTypes()->nonGenericArrayTypes();
// If there are no non-native types, give up
if ($viable_class_types->isEmpty()) {
return '';
}
// Return the first non-native type in the
// list and hope its a class
return (string) $viable_class_types->head();
}
return '';
}
示例13: fromStringInContext
/**
* @param string $type_string
* A '|' delimited string representing a type in the form
* 'int|string|null|ClassName'.
*
* @param Context $context
* The context in which the type string was
* found
*
* @return UnionType
*/
public static function fromStringInContext(string $type_string, Context $context) : UnionType
{
if (empty($type_string)) {
return new UnionType();
}
// If our scope has a generic type identifier defined on it
// that matches the type string, return that UnionType.
if ($context->getScope()->hasTemplateType($type_string)) {
return $context->getScope()->getTemplateType($type_string)->asUnionType();
}
return new UnionType(array_map(function (string $type_name) use($context, $type_string) {
assert($type_name !== '', "Type cannot be empty.");
return Type::fromStringInContext($type_name, $context);
}, array_filter(array_map(function (string $type_name) {
return trim($type_name);
}, explode('|', $type_string)))));
}