PHP_CodeSniffer
[ class tree: PHP_CodeSniffer ] [ index: PHP_CodeSniffer ] [ all elements ]

Source for file FunctionSpacingSniff.php

Documentation is available at FunctionSpacingSniff.php

  1. <?php
  2. /**
  3.  * Checks the separation between methods in a class or interface.
  4.  *
  5.  * @author    Greg Sherwood <gsherwood@squiz.net>
  6.  * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
  7.  * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
  8.  */
  9.  
  10. namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace;
  11.  
  12. use PHP_CodeSniffer\Sniffs\Sniff;
  13. use PHP_CodeSniffer\Files\File;
  14.  
  15. class FunctionSpacingSniff implements Sniff
  16. {
  17.  
  18.     /**
  19.      * The number of blank lines between functions.
  20.      *
  21.      * @var integer 
  22.      */
  23.     public $spacing = 2;
  24.  
  25.  
  26.     /**
  27.      * Returns an array of tokens this test wants to listen for.
  28.      *
  29.      * @return array 
  30.      */
  31.     public function register()
  32.     {
  33.         return array(T_FUNCTION);
  34.  
  35.     }//end register()
  36.  
  37.  
  38.     /**
  39.      * Processes this sniff when one of its tokens is encountered.
  40.      *
  41.      * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
  42.      * @param int                         $stackPtr  The position of the current token
  43.      *                                                in the stack passed in $tokens.
  44.      *
  45.      * @return void 
  46.      */
  47.     public function process(File $phpcsFile, $stackPtr)
  48.     {
  49.         $tokens        = $phpcsFile->getTokens();
  50.         $this->spacing = (int) $this->spacing;
  51.  
  52.         /*
  53.             Check the number of blank lines
  54.             after the function.
  55.         */
  56.  
  57.         if (isset($tokens[$stackPtr]['scope_closer']) === false) {
  58.             // Must be an interface method, so the closer is the semicolon.
  59.             $closer = $phpcsFile->findNext(T_SEMICOLON, $stackPtr);
  60.         } else {
  61.             $closer = $tokens[$stackPtr]['scope_closer'];
  62.         }
  63.  
  64.         // Allow for comments on the same line as the closer.
  65.         for ($nextLineToken = ($closer + 1); $nextLineToken < $phpcsFile->numTokens; $nextLineToken++) {
  66.             if ($tokens[$nextLineToken]['line'] !== $tokens[$closer]['line']) {
  67.                 break;
  68.             }
  69.         }
  70.  
  71.         $foundLines = 0;
  72.         if ($nextLineToken === ($phpcsFile->numTokens - 1)) {
  73.             // We are at the end of the file.
  74.             // Don't check spacing after the function because this
  75.             // should be done by an EOF sniff.
  76.             $foundLines = $this->spacing;
  77.         } else {
  78.             $nextContent = $phpcsFile->findNext(T_WHITESPACE, $nextLineToken, null, true);
  79.             if ($nextContent === false) {
  80.                 // We are at the end of the file.
  81.                 // Don't check spacing after the function because this
  82.                 // should be done by an EOF sniff.
  83.                 $foundLines = $this->spacing;
  84.             } else {
  85.                 $foundLines += ($tokens[$nextContent]['line'] - $tokens[$nextLineToken]['line']);
  86.             }
  87.         }
  88.  
  89.         if ($foundLines !== $this->spacing) {
  90.             $error = 'Expected %s blank line';
  91.             if ($this->spacing !== 1) {
  92.                 $error .= 's';
  93.             }
  94.  
  95.             $error .= ' after function; %s found';
  96.             $data   = array(
  97.                        $this->spacing,
  98.                        $foundLines,
  99.                       );
  100.  
  101.             $fix = $phpcsFile->addFixableError($error, $closer, 'After', $data);
  102.             if ($fix === true) {
  103.                 $phpcsFile->fixer->beginChangeset();
  104.                 for ($i = $nextLineToken; $i <= $nextContent; $i++) {
  105.                     if ($tokens[$i]['line'] === $tokens[$nextContent]['line']) {
  106.                         $phpcsFile->fixer->addContentBefore($i, str_repeat($phpcsFile->eolChar, $this->spacing));
  107.                         break;
  108.                     }
  109.  
  110.                     $phpcsFile->fixer->replaceToken($i, '');
  111.                 }
  112.  
  113.                 $phpcsFile->fixer->endChangeset();
  114.             }//end if
  115.         }//end if
  116.  
  117.         /*
  118.             Check the number of blank lines
  119.             before the function.
  120.         */
  121.  
  122.         $prevLineToken = null;
  123.         for ($i = $stackPtr; $i > 0; $i--) {
  124.             if (strpos($tokens[$i]['content'], $phpcsFile->eolChar) === false) {
  125.                 continue;
  126.             } else {
  127.                 $prevLineToken = $i;
  128.                 break;
  129.             }
  130.         }
  131.  
  132.         if (is_null($prevLineToken) === true) {
  133.             // Never found the previous line, which means
  134.             // there are 0 blank lines before the function.
  135.             $foundLines  = 0;
  136.             $prevContent = 0;
  137.         } else {
  138.             $currentLine = $tokens[$stackPtr]['line'];
  139.  
  140.             $prevContent = $phpcsFile->findPrevious(T_WHITESPACE, $prevLineToken, null, true);
  141.             if ($tokens[$prevContent]['code'] === T_COMMENT) {
  142.                 // Ignore comments as they can have different spacing rules, and this
  143.                 // isn't a proper function comment anyway.
  144.                 return;
  145.             }
  146.  
  147.             if ($tokens[$prevContent]['code'] === T_DOC_COMMENT_CLOSE_TAG
  148.                 && $tokens[$prevContent]['line'] === ($currentLine - 1)
  149.             ) {
  150.                 // Account for function comments.
  151.                 $prevContent = $phpcsFile->findPrevious(T_WHITESPACE, ($tokens[$prevContent]['comment_opener'] - 1), null, true);
  152.             }
  153.  
  154.             // Before we throw an error, check that we are not throwing an error
  155.             // for another function. We don't want to error for no blank lines after
  156.             // the previous function and no blank lines before this one as well.
  157.             $prevLine   = ($tokens[$prevContent]['line'] - 1);
  158.             $i          = ($stackPtr - 1);
  159.             $foundLines = 0;
  160.             while ($currentLine !== $prevLine && $currentLine > 1 && $i > 0) {
  161.                 if (isset($tokens[$i]['scope_condition']) === true) {
  162.                     $scopeCondition = $tokens[$i]['scope_condition'];
  163.                     if ($tokens[$scopeCondition]['code'] === T_FUNCTION) {
  164.                         // Found a previous function.
  165.                         return;
  166.                     }
  167.                 } else if ($tokens[$i]['code'] === T_FUNCTION) {
  168.                     // Found another interface function.
  169.                     return;
  170.                 }
  171.  
  172.                 $currentLine = $tokens[$i]['line'];
  173.                 if ($currentLine === $prevLine) {
  174.                     break;
  175.                 }
  176.  
  177.                 if ($tokens[($i - 1)]['line'] < $currentLine && $tokens[($i + 1)]['line'] > $currentLine) {
  178.                     // This token is on a line by itself. If it is whitespace, the line is empty.
  179.                     if ($tokens[$i]['code'] === T_WHITESPACE) {
  180.                         $foundLines++;
  181.                     }
  182.                 }
  183.  
  184.                 $i--;
  185.             }//end while
  186.         }//end if
  187.  
  188.         if ($foundLines !== $this->spacing) {
  189.             $error = 'Expected %s blank line';
  190.             if ($this->spacing !== 1) {
  191.                 $error .= 's';
  192.             }
  193.  
  194.             $error .= ' before function; %s found';
  195.             $data   = array(
  196.                        $this->spacing,
  197.                        $foundLines,
  198.                       );
  199.  
  200.             $fix = $phpcsFile->addFixableError($error, $stackPtr, 'Before', $data);
  201.             if ($fix === true) {
  202.                 if ($prevContent === 0) {
  203.                     $nextSpace = 0;
  204.                 } else {
  205.                     $nextSpace = $phpcsFile->findNext(T_WHITESPACE, ($prevContent + 1), $stackPtr);
  206.                     if ($nextSpace === false) {
  207.                         $nextSpace = ($stackPtr - 1);
  208.                     }
  209.                 }
  210.  
  211.                 if ($foundLines < $this->spacing) {
  212.                     $padding = str_repeat($phpcsFile->eolChar, ($this->spacing - $foundLines));
  213.                     $phpcsFile->fixer->addContent($nextSpace, $padding);
  214.                 } else {
  215.                     $nextContent = $phpcsFile->findNext(T_WHITESPACE, ($nextSpace + 1), null, true);
  216.                     $phpcsFile->fixer->beginChangeset();
  217.                     for ($i = $nextSpace; $i < ($nextContent - 1); $i++) {
  218.                         $phpcsFile->fixer->replaceToken($i, '');
  219.                     }
  220.  
  221.                     $phpcsFile->fixer->replaceToken($i, str_repeat($phpcsFile->eolChar, $this->spacing));
  222.                     $phpcsFile->fixer->endChangeset();
  223.                 }
  224.             }//end if
  225.         }//end if
  226.  
  227.     }//end process()
  228.  
  229.  
  230. }//end class

Documentation generated on Mon, 11 Mar 2019 15:27:32 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.