function VariableAnalysisSniff::processVariable
* Process a normal variable in the code. * * Most importantly, this function determines if the variable use is a "read" * (using the variable for something) or a "write" (an assignment) or, * sometimes, both at once. * * It also determines the scope of the variable (where it begins and ends). * * Using these two pieces of information, we can determine if the variable is * being used ("read") without having been defined ("write"). * * We can also determine, once the scan has hit the end of a scope, if any of * the variables within that scope have been defined ("write") without being * used ("read"). That behavior, however, happens in the `processScopeClose()` * function using the data gathered by this function. * * Some variables are used in more complex ways, so there are other similar * functions to this one, like `processVariableInString`, and * `processCompact`. They have the same purpose as this function, though. * * If the 'ignore-for-loops' option is true, we will ignore the special * processing for the increment variables of for loops. This will prevent * infinite loops. * *
Parameters
File $phpcsFile The PHP_CodeSniffer file where this token was found.: * @param int $stackPtr The position where the token was found. * @param array<string, bool|string|int> $options See above. * * @return void
2 calls to VariableAnalysisSniff::processVariable()
- VariableAnalysisSniff::process in vendor/
sirbrillig/ phpcs-variable-analysis/ VariableAnalysis/ Sniffs/ CodeAnalysis/ VariableAnalysisSniff.php - * Scan and process a token. * * This is the main processing function of the sniff. Will run on every token * for which `register()` returns true. * *
- VariableAnalysisSniff::processClosingForLoopsAt in vendor/
sirbrillig/ phpcs-variable-analysis/ VariableAnalysis/ Sniffs/ CodeAnalysis/ VariableAnalysisSniff.php - * Scan variables that were postponed because they exist in the increment expression of a for loop. * *
File
-
vendor/
sirbrillig/ phpcs-variable-analysis/ VariableAnalysis/ Sniffs/ CodeAnalysis/ VariableAnalysisSniff.php, line 1588
Class
Namespace
VariableAnalysis\Sniffs\CodeAnalysisCode
protected function processVariable(File $phpcsFile, $stackPtr, $options = []) {
$tokens = $phpcsFile->getTokens();
$token = $tokens[$stackPtr];
// Get the name of the variable.
$varName = Helpers::normalizeVarName($token['content']);
Helpers::debug("examining token for variable '{$varName}' on line {$token['line']}", $token);
// Find the start of the current scope.
$currScope = Helpers::findVariableScope($phpcsFile, $stackPtr);
if ($currScope === null) {
Helpers::debug('no scope found');
return;
}
Helpers::debug("start of scope for variable '{$varName}' is", $currScope);
// Determine if variable is being assigned ("write") or used ("read").
// Read methods that preempt assignment:
// Are we a $object->$property type symbolic reference?
// Possible assignment methods:
// Is a mandatory function/closure parameter
// Is an optional function/closure parameter with non-null value
// Is closure use declaration of a variable defined within containing scope
// catch (...) block start
// $this within a class.
// $GLOBALS, $_REQUEST, etc superglobals.
// $var part of class::$var static member
// Assignment via =
// Assignment via list (...) =
// Declares as a global
// Declares as a static
// Assignment via foreach (... as ...) { }
// Pass-by-reference to known pass-by-reference function
// Are we inside the third expression of a for loop? Store such variables
// for processing after the loop ends by `processClosingForLoopsAt()`.
if (empty($options['ignore-for-loops'])) {
$forLoop = Helpers::getForLoopForIncrementVariable($stackPtr, $this->forLoops);
if ($forLoop) {
Helpers::debug('found variable inside for loop third expression');
$varInfo = $this->getOrCreateVariableInfo($varName, $currScope);
$forLoop->incrementVariables[$stackPtr] = $varInfo;
return;
}
}
// Are we a $object->$property type symbolic reference?
if ($this->processVariableAsSymbolicObjectProperty($phpcsFile, $stackPtr, $varName, $currScope)) {
Helpers::debug('found symbolic object property');
return;
}
// Are we a function or closure parameter?
if (Helpers::isTokenFunctionParameter($phpcsFile, $stackPtr)) {
Helpers::debug('found function definition parameter');
$this->processVariableAsFunctionParameter($phpcsFile, $stackPtr, $varName, $currScope);
return;
}
// Are we a variable being imported into a function's scope with "use"?
if (Helpers::isTokenInsideFunctionUseImport($phpcsFile, $stackPtr)) {
Helpers::debug('found use scope import definition');
$this->processVariableAsUseImportDefinition($phpcsFile, $stackPtr, $varName, $currScope);
return;
}
// Are we a catch parameter?
if ($this->processVariableAsCatchBlock($phpcsFile, $stackPtr, $varName, $currScope)) {
Helpers::debug('found catch block');
return;
}
// Are we $this within a class?
if ($this->processVariableAsThisWithinClass($phpcsFile, $stackPtr, $varName)) {
Helpers::debug('found this usage within a class');
return;
}
// Are we a $GLOBALS, $_REQUEST, etc superglobal?
if ($this->processVariableAsSuperGlobal($varName)) {
Helpers::debug('found superglobal');
return;
}
// Check for static members used outside a class
if ($this->processVariableAsStaticOutsideClass($phpcsFile, $stackPtr, $varName)) {
Helpers::debug('found static usage outside of class');
return;
}
// $var part of class::$var static member
if ($this->processVariableAsStaticMember($phpcsFile, $stackPtr)) {
Helpers::debug('found static member');
return;
}
if ($this->processVariableAsClassProperty($phpcsFile, $stackPtr)) {
Helpers::debug('found class property definition');
return;
}
// Is the next non-whitespace an assignment?
if (Helpers::isTokenInsideAssignmentLHS($phpcsFile, $stackPtr)) {
Helpers::debug('found assignment');
$this->processVariableAsAssignment($phpcsFile, $stackPtr, $varName, $currScope);
if (Helpers::isTokenInsideAssignmentRHS($phpcsFile, $stackPtr) || Helpers::isTokenInsideFunctionCallArgument($phpcsFile, $stackPtr)) {
Helpers::debug("found assignment that's also inside an expression");
$this->markVariableRead($varName, $stackPtr, $currScope);
return;
}
return;
}
// OK, are we within a list (...) = construct?
if ($this->processVariableAsListAssignment($phpcsFile, $stackPtr, $varName, $currScope)) {
Helpers::debug('found list assignment');
return;
}
// OK, are we within a [...] = construct?
if ($this->processVariableAsListShorthandAssignment($phpcsFile, $stackPtr, $varName, $currScope)) {
Helpers::debug('found list shorthand assignment');
return;
}
// Are we a global declaration?
if ($this->processVariableAsGlobalDeclaration($phpcsFile, $stackPtr, $varName, $currScope)) {
Helpers::debug('found global declaration');
return;
}
// Are we a static declaration?
if ($this->processVariableAsStaticDeclaration($phpcsFile, $stackPtr, $varName, $currScope)) {
Helpers::debug('found static declaration');
return;
}
// Are we a foreach loopvar?
if ($this->processVariableAsForeachLoopVar($phpcsFile, $stackPtr, $varName, $currScope)) {
Helpers::debug('found foreach loop variable');
return;
}
// Are we pass-by-reference to known pass-by-reference function?
if ($this->processVariableAsPassByReferenceFunctionCall($phpcsFile, $stackPtr, $varName, $currScope)) {
Helpers::debug('found pass by reference');
return;
}
// Are we a numeric variable used for constructs like preg_replace?
if (Helpers::isVariableANumericVariable($varName)) {
Helpers::debug('found numeric variable');
return;
}
if (Helpers::isVariableInsideElseCondition($phpcsFile, $stackPtr) || Helpers::isVariableInsideElseBody($phpcsFile, $stackPtr)) {
Helpers::debug('found variable inside else condition or body');
$this->processVaribleInsideElse($phpcsFile, $stackPtr, $varName, $currScope);
return;
}
// Are we an isset or empty call?
if (Helpers::isVariableInsideIssetOrEmpty($phpcsFile, $stackPtr)) {
Helpers::debug('found isset or empty');
$this->markVariableRead($varName, $stackPtr, $currScope);
return;
}
// OK, we don't appear to be a write to the var, assume we're a read.
Helpers::debug('looks like a variable read');
$this->markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $stackPtr, $currScope);
}