1<?php
2/**
3 * PSR2_Sniffs_WhiteSpace_ControlStructureSpacingSniff.
4 *
5 * PHP version 5
6 *
7 * @category  PHP
8 * @package   PHP_CodeSniffer
9 * @author    Greg Sherwood <gsherwood@squiz.net>
10 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
11 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
12 * @link      http://pear.php.net/package/PHP_CodeSniffer
13 */
14
15/**
16 * PSR2_Sniffs_WhiteSpace_ControlStructureSpacingSniff.
17 *
18 * Checks that control structures have the correct spacing around brackets.
19 *
20 * @category  PHP
21 * @package   PHP_CodeSniffer
22 * @author    Greg Sherwood <gsherwood@squiz.net>
23 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
24 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
25 * @version   Release: @package_version@
26 * @link      http://pear.php.net/package/PHP_CodeSniffer
27 */
28class PSR2_Sniffs_ControlStructures_ControlStructureSpacingSniff implements PHP_CodeSniffer_Sniff
29{
30
31
32    /**
33     * How many spaces should follow the opening bracket.
34     *
35     * @var int
36     */
37    public $requiredSpacesAfterOpen = 0;
38
39    /**
40     * How many spaces should precede the closing bracket.
41     *
42     * @var int
43     */
44    public $requiredSpacesBeforeClose = 0;
45
46
47    /**
48     * Returns an array of tokens this test wants to listen for.
49     *
50     * @return array
51     */
52    public function register()
53    {
54        return array(
55                T_IF,
56                T_WHILE,
57                T_FOREACH,
58                T_FOR,
59                T_SWITCH,
60                T_DO,
61                T_ELSE,
62                T_ELSEIF,
63                T_TRY,
64                T_CATCH,
65               );
66
67    }//end register()
68
69
70    /**
71     * Processes this test, when one of its tokens is encountered.
72     *
73     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
74     * @param int                  $stackPtr  The position of the current token
75     *                                        in the stack passed in $tokens.
76     *
77     * @return void
78     */
79    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
80    {
81        $this->requiredSpacesAfterOpen   = (int) $this->requiredSpacesAfterOpen;
82        $this->requiredSpacesBeforeClose = (int) $this->requiredSpacesBeforeClose;
83        $tokens = $phpcsFile->getTokens();
84
85        if (isset($tokens[$stackPtr]['parenthesis_opener']) === false
86            || isset($tokens[$stackPtr]['parenthesis_closer']) === false
87        ) {
88            return;
89        }
90
91        $parenOpener    = $tokens[$stackPtr]['parenthesis_opener'];
92        $parenCloser    = $tokens[$stackPtr]['parenthesis_closer'];
93        $spaceAfterOpen = 0;
94        if ($tokens[($parenOpener + 1)]['code'] === T_WHITESPACE) {
95            if (strpos($tokens[($parenOpener + 1)]['content'], $phpcsFile->eolChar) !== false) {
96                $spaceAfterOpen = 'newline';
97            } else {
98                $spaceAfterOpen = strlen($tokens[($parenOpener + 1)]['content']);
99            }
100        }
101
102        $phpcsFile->recordMetric($stackPtr, 'Spaces after control structure open parenthesis', $spaceAfterOpen);
103
104        if ($spaceAfterOpen !== $this->requiredSpacesAfterOpen) {
105            $error = 'Expected %s spaces after opening bracket; %s found';
106            $data  = array(
107                      $this->requiredSpacesAfterOpen,
108                      $spaceAfterOpen,
109                     );
110            $fix   = $phpcsFile->addFixableError($error, ($parenOpener + 1), 'SpacingAfterOpenBrace', $data);
111            if ($fix === true) {
112                $padding = str_repeat(' ', $this->requiredSpacesAfterOpen);
113                if ($spaceAfterOpen === 0) {
114                    $phpcsFile->fixer->addContent($parenOpener, $padding);
115                } else if ($spaceAfterOpen === 'newline') {
116                    $phpcsFile->fixer->replaceToken(($parenOpener + 1), '');
117                } else {
118                    $phpcsFile->fixer->replaceToken(($parenOpener + 1), $padding);
119                }
120            }
121        }
122
123        if ($tokens[$parenOpener]['line'] === $tokens[$parenCloser]['line']) {
124            $spaceBeforeClose = 0;
125            if ($tokens[($parenCloser - 1)]['code'] === T_WHITESPACE) {
126                $spaceBeforeClose = strlen(ltrim($tokens[($parenCloser - 1)]['content'], $phpcsFile->eolChar));
127            }
128
129            $phpcsFile->recordMetric($stackPtr, 'Spaces before control structure close parenthesis', $spaceBeforeClose);
130
131            if ($spaceBeforeClose !== $this->requiredSpacesBeforeClose) {
132                $error = 'Expected %s spaces before closing bracket; %s found';
133                $data  = array(
134                          $this->requiredSpacesBeforeClose,
135                          $spaceBeforeClose,
136                         );
137                $fix   = $phpcsFile->addFixableError($error, ($parenCloser - 1), 'SpaceBeforeCloseBrace', $data);
138                if ($fix === true) {
139                    $padding = str_repeat(' ', $this->requiredSpacesBeforeClose);
140                    if ($spaceBeforeClose === 0) {
141                        $phpcsFile->fixer->addContentBefore($parenCloser, $padding);
142                    } else {
143                        $phpcsFile->fixer->replaceToken(($parenCloser - 1), $padding);
144                    }
145                }
146            }
147        }//end if
148
149    }//end process()
150
151
152}//end class
153