The PHPStan\Analyser\Scope object can be used to get more information about the code, like types of variables, or current file and namespace.

It’s passed as a method parameter to these types of extensions:

The Scope represents the state of the analyser in the position in the AST where the extension is being executed.

public function doFoo(?array $list): void
// Scope knows we're in doFoo() method here
// And it knows that $list is either an array or null
if ($list !== null) {
// Scope knows that $list is an array
$foo = true;
// Scope knows that $foo is true
} else {
// Scope knows that $list is null
$foo = false;
// Scope knows that $foo is false

// Scope knows that $list is either an array or null
// Scope knows that $foo is bool

The most interesting method is Scope::getType(PhpParser\Node\Expr $expr): PHPStan\Type\Type. It allows us to ask for types of expressions like this:

// $methodCall is PhpParser\Node\Expr\MethodCall
// On which type was the method called?
$calledOnType = $scope->getType($methodCall->var);

The getType() method returns an implementation of PHPStan\Type\Type. You can learn more about types in the article about the type system.

Where are we? #

You can use different Scope methods to ask about the current whereabouts:

  • getFile() - returns the current file path
  • getNamespace() - returns the current namespace
  • isInClass() - tells the caller whether we are in a class
  • getClassReflection() - returns the reflection of the current class. Cannot return null if isInClass() is true.
  • isInTrait() - tells the caller whether we are in a trait
  • getTraitReflection() - returns the reflection of the current trait. Cannot return null if isInTrait() is true.
  • getFunction() - returns FunctionReflection, MethodReflection, or null.
  • isInAnonymousFunction() - tells the caller whether we are in an anonymous function
  • getAnonymousFunctionReflection() - returns anonymous function reflection, or null.

Resolving special names #

Although the instances of PhpParser\Node\Name in the AST in case of relative names are resolved according to the current namespace and use statements, certain special names like self remain unresolved.

For example we can have PhpParser\Node\Expr\StaticCall that represents static method call like self::doFoo(). If we were to use the value in its $class property as a definitive class name, we’d work with self, but there’s no class self defined in our code. We first need to resolve self to the correct name:

// $staticCall is PhpParser\Node\Expr\StaticCall
$className = $scope->resolveName($staticCall->class);

Edit this page on GitHub

© 2016–2021 Ondřej Mirtes