public getClassFromReflection ( ReflectionClass $reflectionClass ) : |
||
$reflectionClass | ReflectionClass | |
return |
private function processNode(\PhpParser\Node $node, Scope $scope, \Closure $nodeCallback) { $nodeCallback($node, $scope); if ($node instanceof \PhpParser\Node\Stmt\ClassLike) { if ($node instanceof Node\Stmt\Trait_) { return; } if (isset($node->namespacedName)) { $scope = $scope->enterClass((string) $node->namespacedName); } else { $scope = $scope->enterAnonymousClass($this->anonymousClassReflection); } } elseif ($node instanceof Node\Stmt\TraitUse) { $this->processTraitUse($node, $scope, $nodeCallback); } elseif ($node instanceof \PhpParser\Node\Stmt\Function_) { $scope = $scope->enterFunction($this->broker->getFunction($node->namespacedName, $scope)); } elseif ($node instanceof \PhpParser\Node\Stmt\ClassMethod) { $scope = $this->enterClassMethod($scope, $node); } elseif ($node instanceof \PhpParser\Node\Stmt\Namespace_) { $scope = $scope->enterNamespace((string) $node->name); } elseif ($node instanceof \PhpParser\Node\Expr\StaticCall && (is_string($node->class) || $node->class instanceof \PhpParser\Node\Name) && is_string($node->name) && (string) $node->class === 'Closure' && $node->name === 'bind') { $thisType = null; if (isset($node->args[1])) { $argValue = $node->args[1]->value; if ($argValue instanceof Expr\ConstFetch && (string) $argValue->name === 'null') { $thisType = null; } else { $thisType = $scope->getType($argValue); } } $scopeClass = 'static'; if (isset($node->args[2])) { $argValue = $node->args[2]->value; $argValueType = $scope->getType($argValue); if ($argValueType->getClass() !== null) { $scopeClass = $argValueType->getClass(); } elseif ($argValue instanceof Expr\ClassConstFetch && $argValue->name === 'class' && $argValue->class instanceof Name) { $resolvedName = $scope->resolveName($argValue->class); if ($resolvedName !== null) { $scopeClass = $resolvedName; } } elseif ($argValue instanceof Node\Scalar\String_) { $scopeClass = $argValue->value; } } $closureBindScope = $scope->enterClosureBind($thisType, $scopeClass); } elseif ($node instanceof \PhpParser\Node\Expr\Closure) { $scope = $scope->enterAnonymousFunction($node->params, $node->uses, $node->returnType); } elseif ($node instanceof Foreach_) { if ($node->valueVar instanceof Variable) { $scope = $scope->enterForeach($node->expr, $node->valueVar->name, $node->keyVar !== null && $node->keyVar instanceof Variable ? $node->keyVar->name : null); } else { if ($node->keyVar !== null && $node->keyVar instanceof Variable) { $scope = $scope->assignVariable($node->keyVar->name); } if ($node->valueVar instanceof Array_) { $scope = $this->lookForArrayDestructuringArray($scope, $node->valueVar); } else { $scope = $this->lookForAssigns($scope, $node->valueVar); } } } elseif ($node instanceof Catch_) { if (isset($node->types)) { $nodeTypes = $node->types; } elseif (isset($node->type)) { $nodeTypes = [$node->type]; } else { throw new \PHPStan\ShouldNotHappenException(); } $scope = $scope->enterCatch($nodeTypes, $node->var); } elseif ($node instanceof For_) { foreach ($node->init as $initExpr) { $scope = $this->lookForAssigns($scope, $initExpr); } foreach ($node->cond as $condExpr) { $scope = $this->lookForAssigns($scope, $condExpr); } foreach ($node->loop as $loopExpr) { $scope = $this->lookForAssigns($scope, $loopExpr); } } elseif ($node instanceof If_) { $scope = $this->lookForAssigns($scope, $node->cond); $ifScope = $scope; $scope = $this->lookForTypeSpecifications($scope, $node->cond); $this->processNode($node->cond, $scope, $nodeCallback); $this->processNodes($node->stmts, $scope, $nodeCallback); foreach ($node->elseifs as $elseif) { $this->processNode($elseif, $ifScope, $nodeCallback); $ifScope = $this->lookForAssigns($ifScope, $elseif->cond); } if ($node->else !== null) { $this->processNode($node->else, $ifScope, $nodeCallback); } return; } elseif ($node instanceof Switch_) { $scope = $this->lookForAssigns($scope, $node->cond); $switchScope = $scope; $switchConditionIsTrue = $node->cond instanceof Expr\ConstFetch && strtolower((string) $node->cond->name) === 'true'; foreach ($node->cases as $caseNode) { if ($caseNode->cond !== null) { $switchScope = $this->lookForAssigns($switchScope, $caseNode->cond); if ($switchConditionIsTrue) { $switchScope = $this->lookForTypeSpecifications($switchScope, $caseNode->cond); } } $this->processNode($caseNode, $switchScope, $nodeCallback); if ($this->hasEarlyTermination($caseNode->stmts, $switchScope)) { $switchScope = $scope; } } return; } elseif ($node instanceof ElseIf_) { $scope = $this->lookForAssigns($scope, $node->cond); $scope = $this->lookForTypeSpecifications($scope, $node->cond); } elseif ($node instanceof While_) { $scope = $this->lookForAssigns($scope, $node->cond); $scope = $this->lookForTypeSpecifications($scope, $node->cond); } elseif ($this->polluteCatchScopeWithTryAssignments && $node instanceof TryCatch) { foreach ($node->stmts as $statement) { $scope = $this->lookForAssigns($scope, $statement); } } elseif ($node instanceof Ternary) { $scope = $this->lookForAssigns($scope, $node->cond); } elseif ($node instanceof Do_) { foreach ($node->stmts as $statement) { $scope = $this->lookForAssigns($scope, $statement); } } elseif ($node instanceof FuncCall) { $scope = $scope->enterFunctionCall($node); } elseif ($node instanceof Expr\StaticCall) { $scope = $scope->enterFunctionCall($node); } elseif ($node instanceof MethodCall) { if ($scope->getType($node->var)->getClass() === 'Closure' && $node->name === 'call' && isset($node->args[0])) { $closureCallScope = $scope->enterClosureBind($scope->getType($node->args[0]->value), 'static'); } $scope = $scope->enterFunctionCall($node); } elseif ($node instanceof Array_) { foreach ($node->items as $item) { $scope = $this->lookForAssigns($scope, $item->value); } } elseif ($node instanceof New_ && $node->class instanceof Class_) { $node->args = []; foreach ($node->class->stmts as $i => $statement) { if ($statement instanceof Node\Stmt\ClassMethod && $statement->name === '__construct') { unset($node->class->stmts[$i]); $node->class->stmts = array_values($node->class->stmts); break; } } $code = $this->printer->prettyPrint([$node]); $classReflection = new \ReflectionClass(eval(sprintf('return %s', $code))); $this->anonymousClassReflection = $this->broker->getClassFromReflection($classReflection); } elseif ($node instanceof BooleanNot) { $scope = $scope->enterNegation(); } $originalScope = $scope; foreach ($node->getSubNodeNames() as $subNodeName) { $scope = $originalScope; $subNode = $node->{$subNodeName}; if (is_array($subNode)) { $argClosureBindScope = null; if (isset($closureBindScope) && $subNodeName === 'args') { $argClosureBindScope = $closureBindScope; } $this->processNodes($subNode, $scope, $nodeCallback, $argClosureBindScope); } elseif ($subNode instanceof \PhpParser\Node) { if ($node instanceof Coalesce && $subNodeName === 'left') { $scope = $this->assignVariable($scope, $subNode); } if ($node instanceof Ternary && $subNodeName === 'if') { $scope = $this->lookForTypeSpecifications($scope, $node->cond); } if ($node instanceof BooleanAnd && $subNodeName === 'right') { $scope = $this->lookForTypeSpecifications($scope, $node->left); } if (($node instanceof Assign || $node instanceof AssignRef) && $subNodeName === 'var') { $scope = $this->lookForEnterVariableAssign($scope, $node->var); } $nodeScope = $scope; if ($node instanceof MethodCall && $subNodeName === 'var' && isset($closureCallScope)) { $nodeScope = $closureCallScope; } $this->processNode($subNode, $nodeScope, $nodeCallback); } } }