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

Source for file FunctionDeclarationArgumentSpacingSniff.php

Documentation is available at FunctionDeclarationArgumentSpacingSniff.php

  1. <?php
  2. /**
  3.  * Checks that arguments in function declarations are spaced correctly.
  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\Functions;
  11.  
  12. use PHP_CodeSniffer\Sniffs\Sniff;
  13. use PHP_CodeSniffer\Files\File;
  14.  
  15. class FunctionDeclarationArgumentSpacingSniff implements Sniff
  16. {
  17.  
  18.     /**
  19.      * How many spaces should surround the equals signs.
  20.      *
  21.      * @var integer 
  22.      */
  23.     public $equalsSpacing = 0;
  24.  
  25.     /**
  26.      * How many spaces should follow the opening bracket.
  27.      *
  28.      * @var integer 
  29.      */
  30.     public $requiredSpacesAfterOpen = 0;
  31.  
  32.     /**
  33.      * How many spaces should precede the closing bracket.
  34.      *
  35.      * @var integer 
  36.      */
  37.     public $requiredSpacesBeforeClose = 0;
  38.  
  39.  
  40.     /**
  41.      * Returns an array of tokens this test wants to listen for.
  42.      *
  43.      * @return array 
  44.      */
  45.     public function register()
  46.     {
  47.         return array(
  48.                 T_FUNCTION,
  49.                 T_CLOSURE,
  50.                );
  51.  
  52.     }//end register()
  53.  
  54.  
  55.     /**
  56.      * Processes this test, when one of its tokens is encountered.
  57.      *
  58.      * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
  59.      * @param int                         $stackPtr  The position of the current token in the
  60.      *                                                stack passed in $tokens.
  61.      *
  62.      * @return void 
  63.      */
  64.     public function process(File $phpcsFile, $stackPtr)
  65.     {
  66.         $tokens = $phpcsFile->getTokens();
  67.  
  68.         if (isset($tokens[$stackPtr]['parenthesis_opener']) === false
  69.             || isset($tokens[$stackPtr]['parenthesis_closer']) === false
  70.             || $tokens[$stackPtr]['parenthesis_opener'] === null
  71.             || $tokens[$stackPtr]['parenthesis_closer'] === null
  72.         ) {
  73.             return;
  74.         }
  75.  
  76.         $this->equalsSpacing           = (int) $this->equalsSpacing;
  77.         $this->requiredSpacesAfterOpen = (int) $this->requiredSpacesAfterOpen;
  78.         $this->requiredSpacesBeforeClose = (int) $this->requiredSpacesBeforeClose;
  79.  
  80.         $openBracket = $tokens[$stackPtr]['parenthesis_opener'];
  81.         $this->processBracket($phpcsFile, $openBracket);
  82.  
  83.         if ($tokens[$stackPtr]['code'] === T_CLOSURE) {
  84.             $use = $phpcsFile->findNext(T_USE, ($tokens[$openBracket]['parenthesis_closer'] + 1), $tokens[$stackPtr]['scope_opener']);
  85.             if ($use !== false) {
  86.                 $openBracket = $phpcsFile->findNext(T_OPEN_PARENTHESIS, ($use + 1), null);
  87.                 $this->processBracket($phpcsFile, $openBracket);
  88.             }
  89.         }
  90.  
  91.     }//end process()
  92.  
  93.  
  94.     /**
  95.      * Processes the contents of a single set of brackets.
  96.      *
  97.      * @param \PHP_CodeSniffer\Files\File $phpcsFile   The file being scanned.
  98.      * @param int                         $openBracket The position of the open bracket
  99.      *                                                  in the stack passed in $tokens.
  100.      *
  101.      * @return void 
  102.      */
  103.     public function processBracket($phpcsFile, $openBracket)
  104.     {
  105.         $tokens       = $phpcsFile->getTokens();
  106.         $closeBracket = $tokens[$openBracket]['parenthesis_closer'];
  107.         $multiLine    = ($tokens[$openBracket]['line'] !== $tokens[$closeBracket]['line']);
  108.  
  109.         $nextParam = $openBracket;
  110.         $params    = array();
  111.         while (($nextParam = $phpcsFile->findNext(T_VARIABLE, ($nextParam + 1), $closeBracket)) !== false) {
  112.             $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($nextParam + 1), ($closeBracket + 1), true);
  113.             if ($nextToken === false) {
  114.                 break;
  115.             }
  116.  
  117.             $nextCode = $tokens[$nextToken]['code'];
  118.  
  119.             if ($nextCode === T_EQUAL) {
  120.                 // Check parameter default spacing.
  121.                 $spacesBefore = 0;
  122.                 if (($nextToken - $nextParam) > 1) {
  123.                     $spacesBefore = strlen($tokens[($nextParam + 1)]['content']);
  124.                 }
  125.  
  126.                 if ($spacesBefore !== $this->equalsSpacing) {
  127.                     $error = 'Incorrect spacing between argument "%s" and equals sign; expected '.$this->equalsSpacing.' but found %s';
  128.                     $data  = array(
  129.                               $tokens[$nextParam]['content'],
  130.                               $spacesBefore,
  131.                              );
  132.  
  133.                     $fix = $phpcsFile->addFixableError($error, $nextToken, 'SpaceBeforeEquals', $data);
  134.                     if ($fix === true) {
  135.                         $padding = str_repeat(' ', $this->equalsSpacing);
  136.                         if ($spacesBefore === 0) {
  137.                             $phpcsFile->fixer->addContentBefore($nextToken, $padding);
  138.                         } else {
  139.                             $phpcsFile->fixer->replaceToken(($nextToken - 1), $padding);
  140.                         }
  141.                     }
  142.                 }//end if
  143.  
  144.                 $spacesAfter = 0;
  145.                 if ($tokens[($nextToken + 1)]['code'] === T_WHITESPACE) {
  146.                     $spacesAfter = strlen($tokens[($nextToken + 1)]['content']);
  147.                 }
  148.  
  149.                 if ($spacesAfter !== $this->equalsSpacing) {
  150.                     $error = 'Incorrect spacing between default value and equals sign for argument "%s"; expected '.$this->equalsSpacing.' but found %s';
  151.                     $data  = array(
  152.                               $tokens[$nextParam]['content'],
  153.                               $spacesAfter,
  154.                              );
  155.  
  156.                     $fix = $phpcsFile->addFixableError($error, $nextToken, 'SpaceAfterDefault', $data);
  157.                     if ($fix === true) {
  158.                         $padding = str_repeat(' ', $this->equalsSpacing);
  159.                         if ($spacesAfter === 0) {
  160.                             $phpcsFile->fixer->addContent($nextToken, $padding);
  161.                         } else {
  162.                             $phpcsFile->fixer->replaceToken(($nextToken + 1), $padding);
  163.                         }
  164.                     }
  165.                 }//end if
  166.             }//end if
  167.  
  168.             // Find and check the comma (if there is one).
  169.             $nextComma = $phpcsFile->findNext(T_COMMA, ($nextParam + 1), $closeBracket);
  170.             if ($nextComma !== false) {
  171.                 // Comma found.
  172.                 if ($tokens[($nextComma - 1)]['code'] === T_WHITESPACE) {
  173.                     $error = 'Expected 0 spaces between argument "%s" and comma; %s found';
  174.                     $data  = array(
  175.                               $tokens[$nextParam]['content'],
  176.                               strlen($tokens[($nextComma - 1)]['content']),
  177.                              );
  178.  
  179.                     $fix = $phpcsFile->addFixableError($error, $nextToken, 'SpaceBeforeComma', $data);
  180.                     if ($fix === true) {
  181.                         $phpcsFile->fixer->replaceToken(($nextComma - 1), '');
  182.                     }
  183.                 }
  184.             }
  185.  
  186.             $checkToken = ($nextParam - 1);
  187.             $prev       = $phpcsFile->findPrevious(T_WHITESPACE, $checkToken, null, true);
  188.             if ($tokens[$prev]['code'] === T_ELLIPSIS) {
  189.                 $checkToken = ($prev - 1);
  190.             }
  191.  
  192.             // Take references into account when expecting the
  193.             // location of whitespace.
  194.             if ($phpcsFile->isReference($checkToken) === true) {
  195.                 $whitespace = ($checkToken - 1);
  196.             } else {
  197.                 $whitespace = $checkToken;
  198.             }
  199.  
  200.             if (empty($params) === false) {
  201.                 // This is not the first argument in the function declaration.
  202.                 $arg = $tokens[$nextParam]['content'];
  203.  
  204.                 // Before we throw an error, make sure there is no type hint.
  205.                 $comma     = $phpcsFile->findPrevious(T_COMMA, ($nextParam - 1));
  206.                 $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($comma + 1), null, true);
  207.                 if ($phpcsFile->isReference($nextToken) === true) {
  208.                     $nextToken++;
  209.                 }
  210.  
  211.                 $gap = 0;
  212.                 if ($tokens[$whitespace]['code'] === T_WHITESPACE) {
  213.                     $gap = strlen($tokens[$whitespace]['content']);
  214.                 }
  215.  
  216.                 if ($nextToken !== $nextParam) {
  217.                     // There was a type hint, so check the spacing between
  218.                     // the hint and the variable as well.
  219.                     $hint = $tokens[$nextToken]['content'];
  220.  
  221.                     if ($gap !== 1) {
  222.                         $error = 'Expected 1 space between type hint and argument "%s"; %s found';
  223.                         $data  = array(
  224.                                   $arg,
  225.                                   $gap,
  226.                                  );
  227.                         $fix   = $phpcsFile->addFixableError($error, $nextToken, 'SpacingAfterHint', $data);
  228.                         if ($fix === true) {
  229.                             if ($gap === 0) {
  230.                                 $phpcsFile->fixer->addContent($whitespace, ' ');
  231.                             } else {
  232.                                 $phpcsFile->fixer->replaceToken($whitespace, ' ');
  233.                             }
  234.                         }
  235.                     }
  236.  
  237.                     if ($multiLine === false) {
  238.                         if ($tokens[($comma + 1)]['code'] !== T_WHITESPACE) {
  239.                             $error = 'Expected 1 space between comma and type hint "%s"; 0 found';
  240.                             $data  = array($hint);
  241.                             $fix   = $phpcsFile->addFixableError($error, $nextToken, 'NoSpaceBeforeHint', $data);
  242.                             if ($fix === true) {
  243.                                 $phpcsFile->fixer->addContent($comma, ' ');
  244.                             }
  245.                         } else {
  246.                             $gap = strlen($tokens[($comma + 1)]['content']);
  247.                             if ($gap !== 1) {
  248.                                 $error = 'Expected 1 space between comma and type hint "%s"; %s found';
  249.                                 $data  = array(
  250.                                           $hint,
  251.                                           $gap,
  252.                                          );
  253.                                 $fix   = $phpcsFile->addFixableError($error, $nextToken, 'SpacingBeforeHint', $data);
  254.                                 if ($fix === true) {
  255.                                     $phpcsFile->fixer->replaceToken(($comma + 1), ' ');
  256.                                 }
  257.                             }
  258.                         }//end if
  259.                     }//end if
  260.                 } else {
  261.                     // No type hint.
  262.                     if ($gap === 0) {
  263.                         $error = 'Expected 1 space between comma and argument "%s"; 0 found';
  264.                         $data  = array($arg);
  265.                         $fix   = $phpcsFile->addFixableError($error, $nextToken, 'NoSpaceBeforeArg', $data);
  266.                         if ($fix === true) {
  267.                             $phpcsFile->fixer->addContent($whitespace, ' ');
  268.                         }
  269.                     } else if ($gap !== 1) {
  270.                         // Just make sure this is not actually an indent.
  271.                         if ($tokens[$whitespace]['line'] === $tokens[($whitespace - 1)]['line']) {
  272.                             $error = 'Expected 1 space between comma and argument "%s"; %s found';
  273.                             $data  = array(
  274.                                       $arg,
  275.                                       $gap,
  276.                                      );
  277.  
  278.                             $fix = $phpcsFile->addFixableError($error, $nextToken, 'SpacingBeforeArg', $data);
  279.                             if ($fix === true) {
  280.                                 $phpcsFile->fixer->replaceToken($whitespace, ' ');
  281.                             }
  282.                         }
  283.                     }//end if
  284.                 }//end if
  285.             } else {
  286.                 $gap = 0;
  287.                 if ($tokens[$whitespace]['code'] === T_WHITESPACE) {
  288.                     $gap = strlen($tokens[$whitespace]['content']);
  289.                 }
  290.  
  291.                 $arg = $tokens[$nextParam]['content'];
  292.  
  293.                 // Before we throw an error, make sure there is no type hint.
  294.                 $bracket   = $phpcsFile->findPrevious(T_OPEN_PARENTHESIS, ($nextParam - 1));
  295.                 $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($bracket + 1), null, true);
  296.                 if ($phpcsFile->isReference($nextToken) === true) {
  297.                     $nextToken++;
  298.                 }
  299.  
  300.                 if ($tokens[$nextToken]['code'] !== T_ELLIPSIS && $nextToken !== $nextParam) {
  301.                     // There was a type hint, so check the spacing between
  302.                     // the hint and the variable as well.
  303.                     $hint = $tokens[$nextToken]['content'];
  304.  
  305.                     if ($gap !== 1) {
  306.                         $error = 'Expected 1 space between type hint and argument "%s"; %s found';
  307.                         $data  = array(
  308.                                   $arg,
  309.                                   $gap,
  310.                                  );
  311.                         $fix   = $phpcsFile->addFixableError($error, $nextToken, 'SpacingAfterHint', $data);
  312.                         if ($fix === true) {
  313.                             if ($gap === 0) {
  314.                                 $phpcsFile->fixer->addContent($nextToken, ' ');
  315.                             } else {
  316.                                 $phpcsFile->fixer->replaceToken(($nextToken + 1), ' ');
  317.                             }
  318.                         }
  319.                     }
  320.  
  321.                     $spaceAfterOpen = 0;
  322.                     if ($tokens[($bracket + 1)]['code'] === T_WHITESPACE) {
  323.                         $spaceAfterOpen = strlen($tokens[($bracket + 1)]['content']);
  324.                     }
  325.  
  326.                     if ($multiLine === false && $spaceAfterOpen !== $this->requiredSpacesAfterOpen) {
  327.                         $error = 'Expected %s spaces between opening bracket and type hint "%s"; %s found';
  328.                         $data  = array(
  329.                                   $this->requiredSpacesAfterOpen,
  330.                                   $hint,
  331.                                   $spaceAfterOpen,
  332.                                  );
  333.                         $fix   = $phpcsFile->addFixableError($error, $nextToken, 'SpacingAfterOpenHint', $data);
  334.                         if ($fix === true) {
  335.                             $padding = str_repeat(' ', $this->requiredSpacesAfterOpen);
  336.                             if ($spaceAfterOpen === 0) {
  337.                                 $phpcsFile->fixer->addContent($openBracket, $padding);
  338.                             } else {
  339.                                 $phpcsFile->fixer->replaceToken(($openBracket + 1), $padding);
  340.                             }
  341.                         }
  342.                     }
  343.                 } else if ($multiLine === false && $gap !== $this->requiredSpacesAfterOpen) {
  344.                     $error = 'Expected %s spaces between opening bracket and argument "%s"; %s found';
  345.                     $data  = array(
  346.                               $this->requiredSpacesAfterOpen,
  347.                               $arg,
  348.                               $gap,
  349.                              );
  350.                     $fix   = $phpcsFile->addFixableError($error, $nextToken, 'SpacingAfterOpen', $data);
  351.                     if ($fix === true) {
  352.                         $padding = str_repeat(' ', $this->requiredSpacesAfterOpen);
  353.                         if ($gap === 0) {
  354.                             $phpcsFile->fixer->addContent($openBracket, $padding);
  355.                         } else {
  356.                             $phpcsFile->fixer->replaceToken(($openBracket + 1), $padding);
  357.                         }
  358.                     }
  359.                 }//end if
  360.             }//end if
  361.  
  362.             $params[] = $nextParam;
  363.         }//end while
  364.  
  365.         $gap = 0;
  366.         if ($tokens[($closeBracket - 1)]['code'] === T_WHITESPACE) {
  367.             $gap = strlen($tokens[($closeBracket - 1)]['content']);
  368.         }
  369.  
  370.         if (empty($params) === true) {
  371.             // There are no parameters for this function.
  372.             if (($closeBracket - $openBracket) !== 1) {
  373.                 $error = 'Expected 0 spaces between brackets of function declaration; %s found';
  374.                 $data  = array($gap);
  375.                 $fix   = $phpcsFile->addFixableError($error, $openBracket, 'SpacingBetween', $data);
  376.                 if ($fix === true) {
  377.                     $phpcsFile->fixer->replaceToken(($openBracket + 1), '');
  378.                 }
  379.             }
  380.         } else if ($multiLine === false && $gap !== $this->requiredSpacesBeforeClose) {
  381.             $lastParam = array_pop($params);
  382.             $error     = 'Expected %s spaces between argument "%s" and closing bracket; %s found';
  383.             $data      = array(
  384.                           $this->requiredSpacesBeforeClose,
  385.                           $tokens[$lastParam]['content'],
  386.                           $gap,
  387.                          );
  388.             $fix       = $phpcsFile->addFixableError($error, $closeBracket, 'SpacingBeforeClose', $data);
  389.             if ($fix === true) {
  390.                 $padding = str_repeat(' ', $this->requiredSpacesBeforeClose);
  391.                 if ($gap === 0) {
  392.                     $phpcsFile->fixer->addContentBefore($closeBracket, $padding);
  393.                 } else {
  394.                     $phpcsFile->fixer->replaceToken(($closeBracket - 1), $padding);
  395.                 }
  396.             }
  397.         }//end if
  398.  
  399.     }//end processBracket()
  400.  
  401.  
  402. }//end class

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