Scope
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:
- Custom rules (2nd parameter of
processNode
method) - Dynamic return type extensions (last parameter of
getTypeFrom*Call
methods) - Dynamic throw type extensions (last parameter of
getTypeFrom*Call
methods) - Type-specifying extensions (3rd parameter of
specifyTypes
method)
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 pathgetNamespace()
- returns the current namespaceisInClass()
- tells the caller whether we are in a classgetClassReflection()
- returns the reflection of the current class. Cannot returnnull
ifisInClass()
is true.isInTrait()
- tells the caller whether we are in a traitgetTraitReflection()
- returns the reflection of the current trait. Cannot returnnull
ifisInTrait()
is true.getFunction()
- returnsFunctionReflection
,MethodReflection
, or null.isInAnonymousFunction()
- tells the caller whether we are in an anonymous functiongetAnonymousFunctionReflection()
- returns anonymous function reflection, or null.
Resolving special names #
In the case of relative names, PhpParser\Node\Name
AST node instances are resolved according to the current namespace and use
statements, however 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);