/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsfile The file being scanned. * @param int $stackptr The position of the current token in the * stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); if (isset($tokens[$stackptr]['scope_opener']) === false) { $error = 'possible parse error: '; $error .= $tokens[$stackptr]['content']; $error .= ' missing opening or closing brace'; $phpcsfile->addwarning($error, $stackptr); return; } $curlybrace = $tokens[$stackptr]['scope_opener']; $lastcontent = $phpcsfile->findprevious(T_WHITESPACE, $curlybrace - 1, $stackptr, true); $classline = $tokens[$lastcontent]['line']; $braceline = $tokens[$curlybrace]['line']; if ($braceline != $classline) { $error = 'Opening brace of a '; $error .= $tokens[$stackptr]['content']; $error .= ' must be on the same line as the definition'; $phpcsfile->adderror($error, $curlybrace); return; } if ($tokens[$curlybrace - 1]['code'] === T_WHITESPACE) { $prevcontent = $tokens[$curlybrace - 1]['content']; if ($prevcontent !== $phpcsfile->eolChar) { $blankspace = substr($prevcontent, strpos($prevcontent, $phpcsfile->eolChar)); $spaces = strlen($blankspace); if ($spaces !== 1) { $error = "Expected 1 space before opening brace; {$spaces} found"; $phpcsfile->adderror($error, $curlybrace); } } } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsfile The file being scanned. * @param int $stackptr The position of the current token in the * stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $workingstring = $tokens[$stackptr]['content']; // Check if it's a double quoted string. if (strpos($workingstring, '"') === false) { return; } // Make sure it's not a part of a string started above. // If it is, then we have already checked it. if ($workingstring[0] !== '"') { return; } // Work through the following tokens, in case this string is stretched // over multiple Lines. for ($i = $stackptr + 1; $i < $phpcsfile->numTokens; $i++) { if ($tokens[$i]['type'] !== 'T_CONSTANT_ENCAPSED_STRING') { break; } $workingstring .= $tokens[$i]['content']; } $allowedchars = array('\\n', '\\r', '\\f', '\\t', '\\v', '\\x', '\'', '$'); foreach ($allowedchars as $testchar) { if (strpos($workingstring, $testchar) !== false) { return; } } $error = "String {$workingstring} does not require double quotes; use single quotes instead"; $phpcsfile->addwarning($error, $stackptr); }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsfile The file being scanned. * @param int $stackptr The position of the current token in the * stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $last_token = end($tokens); if ($last_token['code'] === T_CLOSE_TAG) { $error = 'Closing PHP tag is not required at the end of the file. Please remove.'; $phpcsfile->addwarning($error, $stackptr); } }
/** * Process the version tag. * * @param int $errorpos The line number where the error occurs. * * @return void */ protected function processversion($errorpos) { $version = $this->commentparser->getVersion(); if ($version !== null) { $content = $version->getcontent(); $matches = array(); if (empty($content) === true) { $error = 'content missing for @version tag in file comment'; $this->currentfile->adderror($error, $errorpos); } else { if (strstr($content, 'CVS:') === false && strstr($content, 'SVN:') === false) { $error = "Invalid version \"{$content}\" in file comment; consider \"CVS: <cvs_id>\" or \"SVN: <svn_id>\" instead"; $this->currentfile->addwarning($error, $errorpos); } } } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsfile The file being scanned. * @param int $stackptr The position of the current token * in the stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $token = $tokens[$stackptr]; // Skip for-statements without body. if (isset($token['scope_opener']) === false) { return; } // Fetch previous token. $prev = $phpcsfile->findprevious(PHP_CodeSniffer_tokens::$emptyTokens, $stackptr - 1, null, true); // Skip for non final class. if ($prev === false || $tokens[$prev]['code'] !== T_FINAL) { return; } $next = ++$token['scope_opener']; $end = --$token['scope_closer']; for (; $next <= $end; ++$next) { if ($tokens[$next]['code'] === T_FINAL) { $error = 'Unnecessary FINAL modifier in FINAL class'; $phpcsfile->addwarning($error, $next); } } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsfile The file being scanned. * @param int $stackptr The position of the current token * in the stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $token = $tokens[$stackptr]; // Skip for-statements without body. if (isset($token['scope_opener']) === false) { return; } $next = ++$token['scope_opener']; $end = --$token['scope_closer']; $emptybody = true; for (; $next <= $end; ++$next) { if (in_array($tokens[$next]['code'], PHP_CodeSniffer_tokens::$emptyTokens) === false) { $emptybody = false; break; } } if ($emptybody === true) { // Get token identifier. $name = $phpcsfile->gettokensAsString($stackptr, 1); $error = sprintf('Empty %s statement detected', strtoupper($name)); if ($this->_tokens[$token['code']] === true) { $phpcsfile->adderror($error, $stackptr); } else { $phpcsfile->addwarning($error, $stackptr); } } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsfile The file being scanned. * @param int $stackptr The position of the current token in the * stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsfile, $stackptr) { // Modify array of required tags $this->tags['package']['required'] = false; $this->tags['copyright']['required'] = false; $this->tags['author']['required'] = false; $this->currentfile = $phpcsfile; $tokens = $phpcsfile->gettokens(); $type = strtolower($tokens[$stackptr]['content']); $find = array(T_ABSTRACT, T_WHITESPACE, T_FINAL); // Extract the class comment docblock. $commentend = $phpcsfile->findprevious($find, $stackptr - 1, null, true); if ($commentend !== false && $tokens[$commentend]['code'] === T_COMMENT) { $phpcsfile->adderror("You must use \"/**\" style comments for a {$type} comment", $stackptr); return; } else { if ($commentend === false || $tokens[$commentend]['code'] !== T_DOC_COMMENT) { $phpcsfile->adderror("Missing {$type} doc comment", $stackptr); return; } } $commentstart = $phpcsfile->findprevious(T_DOC_COMMENT, $commentend - 1, null, true) + 1; $commentnext = $phpcsfile->findprevious(T_WHITESPACE, $commentend + 1, $stackptr, false, $phpcsfile->eolChar); // Distinguish file and class comment. $prevclasstoken = $phpcsfile->findprevious(T_CLASS, $stackptr - 1); if ($prevclasstoken === false) { // This is the first class token in this file, need extra checks. $prevnoncomment = $phpcsfile->findprevious(T_DOC_COMMENT, $commentstart - 1, null, true); if ($prevnoncomment !== false) { $prevcomment = $phpcsfile->findprevious(T_DOC_COMMENT, $prevnoncomment - 1); if ($prevcomment === false) { // There is only 1 doc comment between open tag and class token. $newlinetoken = $phpcsfile->findnext(T_WHITESPACE, $commentend + 1, $stackptr, false, $phpcsfile->eolChar); if ($newlinetoken !== false) { $newlinetoken = $phpcsfile->findnext(T_WHITESPACE, $newlinetoken + 1, $stackptr, false, $phpcsfile->eolChar); if ($newlinetoken !== false) { // Blank line between the class and the doc block. // The doc block is most likely a file comment. $phpcsfile->adderror("Missing {$type} doc comment", $stackptr + 1); return; } } } } } $comment = $phpcsfile->gettokensAsString($commentstart, $commentend - $commentstart + 1); // Parse the class comment.docblock. try { $this->commentparser = new PHP_CodeSniffer_CommentParser_ClassCommentParser($comment, $phpcsfile); $this->commentparser->parse(); } catch (PHP_CodeSniffer_CommentParser_ParserException $e) { $line = $e->getlinewithinComment() + $commentstart; $phpcsfile->adderror($e->getMessage(), $line); return; } $comment = $this->commentparser->getComment(); if (is_null($comment) === true) { $error = ucfirst($type) . ' doc comment is empty'; $phpcsfile->adderror($error, $commentstart); return; } // No extra newline before short description. $short = $comment->getShortComment(); $newlinecount = 0; $newlinespan = strspn($short, $phpcsfile->eolChar); if ($short !== '' && $newlinespan > 0) { $line = $newlinespan > 1 ? 'newlines' : 'newline'; $error = "Extra {$line} found before {$type} comment short description"; $phpcsfile->adderror($error, $commentstart + 1); } $newlinecount = substr_count($short, $phpcsfile->eolChar) + 1; // Exactly one blank line between short and long description. $long = $comment->getlongcomment(); if (empty($long) === false) { $between = $comment->getWhiteSpacebetween(); $newlinebetween = substr_count($between, $phpcsfile->eolChar); if ($newlinebetween !== 2) { $error = "There must be exactly one blank line between descriptions in {$type} comments"; $phpcsfile->adderror($error, $commentstart + $newlinecount + 1); } $newlinecount += $newlinebetween; } // Exactly one blank line before tags. $tags = $this->commentparser->gettagOrders(); if (count($tags) > 1) { $newlinespan = $comment->getNewlineAfter(); if ($newlinespan !== 2) { $error = "There must be exactly one blank line before the tags in {$type} comments"; if ($long !== '') { $newlinecount += substr_count($long, $phpcsfile->eolChar) - $newlinespan + 1; } $phpcsfile->addwarning($error, $commentstart + $newlinecount); $short = rtrim($short, $phpcsfile->eolChar . ' '); } } // Check each tag. $this->processtags($commentstart, $commentend); }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsfile The file being scanned. * @param int $stackptr The position of the current token * in the stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $token = $tokens[$stackptr]; // Skip broken function declarations. if (isset($token['scope_opener']) === false || isset($token['parenthesis_opener']) === false) { return; } $params = array(); foreach ($phpcsfile->getmethodparameters($stackptr) as $param) { $params[$param['name']] = $stackptr; } $next = ++$token['scope_opener']; $end = --$token['scope_closer']; $emptybody = true; for (; $next <= $end; ++$next) { $token = $tokens[$next]; $code = $token['code']; // Ingorable tokens. if (in_array($code, PHP_CodeSniffer_tokens::$emptyTokens) === true) { continue; } else { if ($code === T_THROW && $emptybody === true) { // Throw statement and an empty body indicate an interface method. return; } else { if ($code === T_RETURN && $emptybody === true) { // Return statement and an empty body indicate an interface method. $tmp = $phpcsfile->findnext(PHP_CodeSniffer_tokens::$emptyTokens, $next + 1, null, true); if ($tmp === false) { return; } // There is a return. if ($tokens[$tmp] === T_SEMICOLON) { return; } $tmp = $phpcsfile->findnext(PHP_CodeSniffer_tokens::$emptyTokens, $tmp + 1, null, true); // There is a return <token>. if ($tmp !== false && $tokens[$tmp] === T_SEMICOLON) { return; } } } } $emptybody = false; if ($code === T_VARIABLE && isset($params[$token['content']]) === true) { unset($params[$token['content']]); } else { if ($code === T_DOUBLE_QUOTED_STRING) { // tokenize double quote string. $strtokens = token_get_all(sprintf('<?php %s;?>', $token['content'])); foreach ($strtokens as $tok) { if (is_array($tok) === false || $tok[0] !== T_VARIABLE) { continue; } if (isset($params[$tok[1]]) === true) { unset($params[$tok[1]]); } } } } } if ($emptybody === false && count($params) > 0) { foreach ($params as $paramname => $position) { $error = 'The method parameter ' . $paramname . ' is never used'; $phpcsfile->addwarning($error, $position); } } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsfile The file being scanned. * @param int $stackptr The position of the current token * in the stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $token = $tokens[$stackptr]; // Skip for-loop without body. if (isset($token['scope_opener']) === false) { return; } // Find incrementors for outer loop. $outer = $this->findincrementers($tokens, $token); // Skip if empty. if (count($outer) === 0) { return; } // Find nested for loops. $start = ++$token['scope_opener']; $end = --$token['scope_closer']; for (; $start <= $end; ++$start) { if ($tokens[$start]['code'] !== T_FOR) { continue; } $inner = $this->findincrementers($tokens, $tokens[$start]); $diff = array_intersect($outer, $inner); if (count($diff) !== 0) { $error = sprintf('Loop incrementor (%s) jumbling with inner loop', join(', ', $diff)); $phpcsfile->addwarning($error, $stackptr); } } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsfile The file being scanned. * @param int $stackptr The position of the current token * in the stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $token = $tokens[$stackptr]; // Skip invalid statement. if (isset($token['parenthesis_opener']) === false) { return; } $next = ++$token['parenthesis_opener']; $end = --$token['parenthesis_closer']; $position = 0; for (; $next <= $end; ++$next) { $code = $tokens[$next]['code']; if ($code === T_SEMICOLON) { ++$position; } if ($position < 1) { continue; } else { if ($position > 1) { break; } else { if ($code !== T_VARIABLE && $code !== T_STRING) { continue; } } } // Find next non empty token, if it is a open curly brace we have a // function call. $index = $phpcsfile->findnext(PHP_CodeSniffer_tokens::$emptyTokens, $next + 1, null, true); if ($tokens[$index]['code'] === T_OPEN_PARENTHESIS) { $error = 'Avoid function calls in a FOR loop test part'; $phpcsfile->addwarning($error, $stackptr); break; } } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsfile The file being scanned. * @param int $stackptr The position of the current token * in the stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $token = $tokens[$stackptr]; // Skip for-loop without body. if (isset($token['parenthesis_opener']) === false) { return; } $next = ++$token['parenthesis_opener']; $end = --$token['parenthesis_closer']; $goodcondition = false; for (; $next <= $end; ++$next) { $code = $tokens[$next]['code']; if (in_array($code, PHP_CodeSniffer_tokens::$emptyTokens) === true) { continue; } else { if ($code !== T_TRUE && $code !== T_FALSE) { $goodcondition = true; } } } if ($goodcondition === false) { $error = 'Avoid IF statements that are always true or false'; $phpcsfile->addwarning($error, $stackptr); } }
/** * Process the function parameter comments. * * @param int $commentstart The position in the stack where * the comment started. * * @return void */ protected function processparams($commentstart) { $realparams = $this->currentfile->getmethodparameters($this->_functiontoken); $params = $this->commentparser->getparams(); $foundparams = array(); if (empty($params) === false) { $lastparm = count($params) - 1; if (substr_count($params[$lastparm]->getwhitespaceafter(), $this->currentfile->eolChar) !== 2) { $error = 'Last parameter comment requires a blank newline after it'; $errorpos = $params[$lastparm]->getline() + $commentstart; $this->currentfile->addwarning($error, $errorpos); } $previousparam = null; $spacebeforevar = 10000; $spacebeforecomment = 10000; $longesttype = 0; $longestvar = 0; foreach ($params as $param) { $paramcomment = trim($param->getcomment()); $errorpos = $param->getline() + $commentstart; // Make sure that there is only one space before the var type. if ($param->getwhitespacebeforetype() !== ' ') { $error = 'Expected 1 space before variable type'; $this->currentfile->addwarning($error, $errorpos); } $spacecount = substr_count($param->getwhitespacebeforevarname(), ' '); if ($spacecount < $spacebeforevar) { $spacebeforevar = $spacecount; $longesttype = $errorpos; } $spacecount = substr_count($param->getwhitespacebeforecomment(), ' '); if ($spacecount < $spacebeforecomment && $paramcomment !== '') { $spacebeforecomment = $spacecount; $longestvar = $errorpos; } // Make sure they are in the correct order, // and have the correct name. $pos = $param->getposition(); $paramname = $param->getvarname() !== '' ? $param->getvarname() : '[ UNKNOWN ]'; if ($previousparam !== null) { $previousname = $previousparam->getvarname() !== '' ? $previousparam->getvarname() : 'UNKNOWN'; // Check to see if the parameters align properly. if ($param->alignsvariablewith($previousparam) === false) { $error = 'The variable names for parameters ' . $previousname . ' (' . ($pos - 1) . ') and ' . $paramname . ' (' . $pos . ') do not align'; $this->currentfile->addwarning($error, $errorpos); } if ($param->alignsCommentWith($previousparam) === false) { $error = 'The comments for parameters ' . $previousname . ' (' . ($pos - 1) . ') and ' . $paramname . ' (' . $pos . ') do not align'; $this->currentfile->addwarning($error, $errorpos); } } // Make sure the names of the parameter comment matches the // actual parameter. if (isset($realparams[$pos - 1]) === true) { $realname = $realparams[$pos - 1]['name']; $foundparams[] = $realname; // Append ampersand to name if passing by reference. if ($realparams[$pos - 1]['pass_by_reference'] === true) { $realname = '&' . $realname; } if ($realname !== $param->getvarname()) { $error = 'Doc comment var "' . $paramname; $error .= '" does not match actual variable name "' . $realname; $error .= '" at position ' . $pos; $this->currentfile->adderror($error, $errorpos); } } else { // We must have an extra parameter comment. $error = 'Superfluous doc comment at position ' . $pos; $this->currentfile->adderror($error, $errorpos); } if ($param->getvarname() === '') { $error = 'Missing parameter name at position ' . $pos; $this->currentfile->adderror($error, $errorpos); } if ($param->gettype() === '') { $error = 'Missing type at position ' . $pos; $this->currentfile->adderror($error, $errorpos); } if ($paramcomment === '') { $error = 'Missing comment for param "' . $paramname . '" at position ' . $pos; $this->currentfile->adderror($error, $errorpos); } $previousparam = $param; } if ($spacebeforevar !== 1 && $spacebeforevar !== 10000 && $spacebeforecomment !== 10000) { $error = 'Expected 1 space after the longest type'; $this->currentfile->adderror($error, $longesttype); } if ($spacebeforecomment !== 1 && $spacebeforecomment !== 10000) { $error = 'Expected 1 space after the longest variable name'; $this->currentfile->adderror($error, $longestvar); } } $realnames = array(); foreach ($realparams as $realparam) { $realnames[] = $realparam['name']; } // Report and missing comments. $diff = array_diff($realnames, $foundparams); foreach ($diff as $neededparam) { if (count($params) !== 0) { $errorpos = $params[count($params) - 1]->getline() + $commentstart; } else { $errorpos = $commentstart; } $error = 'Doc comment for "' . $neededparam . '" missing'; $this->currentfile->adderror($error, $errorpos); } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsfile The file being scanned. * @param int $stackptr The position of the current token * in the stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $token = $tokens[$stackptr]; // Skip invalid statement. if (isset($token['parenthesis_opener']) === false) { return; } $next = ++$token['parenthesis_opener']; $end = --$token['parenthesis_closer']; $parts = array(0, 0, 0); $index = 0; for (; $next <= $end; ++$next) { $code = $tokens[$next]['code']; if ($code === T_SEMICOLON) { ++$index; } else { if (in_array($code, PHP_CodeSniffer_tokens::$emptyTokens) === false) { ++$parts[$index]; } } } if ($parts[0] === 0 && $parts[2] === 0 && $parts[1] > 0) { $error = 'This FOR loop can be simplified to a WHILE loop'; $phpcsfile->addwarning($error, $stackptr); } }
/** * Checks if a line is too long. * * @param PHP_CodeSniffer_File $phpcsfile The file being scanned. * @param int $stackptr The token at the end of the line. * @param string $linecontent The content of the line. * * @return void */ protected function checklinelength(PHP_CodeSniffer_File $phpcsfile, $stackptr, $linecontent) { // If the content is a CVS or SVN id in a version tag, or it is // a license tag with a name and URL, there is nothing the // developer can do to shorten the line, so don't throw errors. if (preg_match('|@version[^\\$]+\\$Id|', $linecontent) === 0 && preg_match('|@license|', $linecontent) === 0) { $linelength = strlen($linecontent); if ($this->absolutelinelimit > 0 && $linelength > $this->absolutelinelimit) { $error = 'line exceeds maximum limit of ' . $this->absolutelinelimit . " characters; contains {$linelength} characters"; $phpcsfile->adderror($error, $stackptr); } else { if ($linelength > $this->linelimit) { $warning = 'line exceeds ' . $this->linelimit . " characters; contains {$linelength} characters"; $phpcsfile->addwarning($warning, $stackptr); } } } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsfile The file being scanned. * @param int $stackptr The position of the current token in the * stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); // Skip tokens that are the names of functions or classes // within their definitions. For example: // function myFunction... // "myFunction" is T_STRING but we should skip because it is not a // function or method *call*. $functionname = $stackptr; $functionkeyword = $phpcsfile->findprevious(PHP_CodeSniffer_tokens::$emptyTokens, $stackptr - 1, null, true); if ($tokens[$functionkeyword]['code'] === T_FUNCTION || $tokens[$functionkeyword]['code'] === T_CLASS) { return; } // If the next non-whitespace token after the function or method call // is not an opening parenthesis then it cant really be a *call*. $openbracket = $phpcsfile->findnext(PHP_CodeSniffer_tokens::$emptyTokens, $functionname + 1, null, true); if ($tokens[$openbracket]['code'] !== T_OPEN_PARENTHESIS) { return; } $closebracket = $tokens[$openbracket]['parenthesis_closer']; $nextseparator = $openbracket; while (($nextseparator = $phpcsfile->findnext(array(T_COMMA, T_VARIABLE), $nextseparator + 1, $closebracket)) !== false) { // Make sure the comma or variable belongs directly to this function call, // and is not inside a nested function call or array. $brackets = $tokens[$nextseparator]['nested_parenthesis']; $lastbracket = array_pop($brackets); if ($lastbracket !== $closebracket) { continue; } if ($tokens[$nextseparator]['code'] === T_COMMA) { if ($tokens[$nextseparator - 1]['code'] === T_WHITESPACE) { $error = 'Space found before comma in function call'; $phpcsfile->addwarning($error, $stackptr); } if ($tokens[$nextseparator + 1]['code'] !== T_WHITESPACE) { $error = 'No space found after comma in function call'; $phpcsfile->addwarning($error, $stackptr); } else { // If there is a newline in the space, then the must be formatting // each argument on a newline, which is valid, so ignore it. if (strpos($tokens[$nextseparator + 1]['content'], $phpcsfile->eolChar) === false) { $space = strlen($tokens[$nextseparator + 1]['content']); if ($space > 1) { $error = 'Expected 1 space after comma in function call; '; $error .= $space . ' found'; $phpcsfile->addwarning($error, $stackptr); } } } } else { // token is a variable. $nexttoken = $phpcsfile->findnext(PHP_CodeSniffer_tokens::$emptyTokens, $nextseparator + 1, $closebracket, true); if ($nexttoken !== false) { if ($tokens[$nexttoken]['code'] === T_EQUAL) { if ($tokens[$nexttoken - 1]['code'] !== T_WHITESPACE) { $error = 'Expected 1 space before = sign of default value'; $phpcsfile->addwarning($error, $stackptr); } if ($tokens[$nexttoken + 1]['code'] !== T_WHITESPACE) { $error = 'Expected 1 space after = sign of default value'; $phpcsfile->addwarning($error, $stackptr); } } } } } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsfile The file being scanned. * @param int $stackptr The position of the current token * in the stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $token = $tokens[$stackptr]; // Skip function without body. if (isset($token['scope_opener']) === false) { return; } // Get function name. $methodname = $phpcsfile->getdeclarationname($stackptr); // Get all parameters from method signature. $signature = array(); foreach ($phpcsfile->getmethodparameters($stackptr) as $param) { $signature[] = $param['name']; } $next = ++$token['scope_opener']; $end = --$token['scope_closer']; for (; $next <= $end; ++$next) { $code = $tokens[$next]['code']; if (in_array($code, PHP_CodeSniffer_tokens::$emptyTokens) === true) { continue; } else { if ($code === T_RETURN) { continue; } } break; } // Any token except 'parent' indicates correct code. if ($tokens[$next]['code'] !== T_PARENT) { return; } // Find next non empty token index, should be double colon. $next = $phpcsfile->findnext(PHP_CodeSniffer_tokens::$emptyTokens, $next + 1, null, true); // Skip for invalid code. if ($next === false || $tokens[$next]['code'] !== T_DOUBLE_COLON) { return; } // Find next non empty token index, should be the function name. $next = $phpcsfile->findnext(PHP_CodeSniffer_tokens::$emptyTokens, $next + 1, null, true); // Skip for invalid code or other method. if ($next === false || $tokens[$next]['content'] !== $methodname) { return; } // Find next non empty token index, should be the open parenthesis. $next = $phpcsfile->findnext(PHP_CodeSniffer_tokens::$emptyTokens, $next + 1, null, true); // Skip for invalid code. if ($next === false || $tokens[$next]['code'] !== T_OPEN_PARENTHESIS) { return; } $validparametertypes = array(T_VARIABLE, T_LNUMBER, T_CONSTANT_ENCAPSED_STRING); $parameters = array(''); $parenthesiscount = 1; $count = count($tokens); for (++$next; $next < $count; ++$next) { $code = $tokens[$next]['code']; if ($code === T_OPEN_PARENTHESIS) { ++$parenthesiscount; } else { if ($code === T_CLOSE_PARENTHESIS) { --$parenthesiscount; } else { if ($parenthesiscount === 1 && $code === T_COMMA) { $parameters[] = ''; } else { if (in_array($code, PHP_CodeSniffer_tokens::$emptyTokens) === false) { $parameters[count($parameters) - 1] .= $tokens[$next]['content']; } } } } if ($parenthesiscount === 0) { break; } } $next = $phpcsfile->findnext(PHP_CodeSniffer_tokens::$emptyTokens, $next + 1, null, true); if ($next === false || $tokens[$next]['code'] !== T_SEMICOLON) { return; } // Check rest of the scope. for (++$next; $next <= $end; ++$next) { $code = $tokens[$next]['code']; // Skip for any other content. if (in_array($code, PHP_CodeSniffer_tokens::$emptyTokens) === false) { return; } } $parameters = array_map('trim', $parameters); $parameters = array_filter($parameters); if (count($parameters) === count($signature) && $parameters === $signature) { $phpcsfile->addwarning('Useless method overriding detected', $stackptr); } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsfile The file being scanned. * @param int $stackptr The position of the current token in the * stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); if (isset($tokens[$stackptr]['scope_opener']) === false) { // Ignore the ELSE in ELSE IF. We'll process the IF part later. if ($tokens[$stackptr]['code'] === T_ELSE && $tokens[$stackptr + 2]['code'] === T_IF) { return; } if ($tokens[$stackptr]['code'] === T_WHILE) { // This could be from a DO WHILE, which doesn't have an opening brace. $lastcontent = $phpcsfile->findprevious(T_WHITESPACE, $stackptr - 1, null, true); if ($tokens[$lastcontent]['code'] === T_CLOSE_CURLY_BRACKET) { $brace = $tokens[$lastcontent]; if (isset($brace['scope_condition']) === true) { $condition = $tokens[$brace['scope_condition']]; if ($condition['code'] === T_DO) { return; } } } } // This is a control structure without an opening brace, // so it is an inline statement. if ($this->error === true) { $phpcsfile->adderror('Inline control structures are not allowed', $stackptr); } else { $phpcsfile->addwarning('Inline control structures are discouraged', $stackptr); } return; } }