1<?php
2/**
3 * Squiz_Sniffs_Strings_EchoedStringsSniff.
4 *
5 * PHP version 5
6 *
7 * @category  PHP
8 * @package   PHP_CodeSniffer
9 * @author    Greg Sherwood <gsherwood@squiz.net>
10 * @author    Marc McIntyre <mmcintyre@squiz.net>
11 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
12 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
13 * @link      http://pear.php.net/package/PHP_CodeSniffer
14 */
15
16/**
17 * Squiz_Sniffs_Strings_EchoedStringsSniff.
18 *
19 * Makes sure that any strings that are "echoed" are not enclosed in brackets
20 * like a function call.
21 *
22 * @category  PHP
23 * @package   PHP_CodeSniffer
24 * @author    Greg Sherwood <gsherwood@squiz.net>
25 * @author    Marc McIntyre <mmcintyre@squiz.net>
26 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
27 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
28 * @version   Release: @package_version@
29 * @link      http://pear.php.net/package/PHP_CodeSniffer
30 */
31class Squiz_Sniffs_Strings_EchoedStringsSniff implements PHP_CodeSniffer_Sniff
32{
33
34
35    /**
36     * Returns an array of tokens this test wants to listen for.
37     *
38     * @return array
39     */
40    public function register()
41    {
42        return array(T_ECHO);
43
44    }//end register()
45
46
47    /**
48     * Processes this test, when one of its tokens is encountered.
49     *
50     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
51     * @param int                  $stackPtr  The position of the current token in the
52     *                                        stack passed in $tokens.
53     *
54     * @return void
55     */
56    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
57    {
58        $tokens = $phpcsFile->getTokens();
59
60        $firstContent = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true);
61        // If the first non-whitespace token is not an opening parenthesis, then we are not concerned.
62        if ($tokens[$firstContent]['code'] !== T_OPEN_PARENTHESIS) {
63            $phpcsFile->recordMetric($stackPtr, 'Brackets around echoed strings', 'no');
64            return;
65        }
66
67        $end = $phpcsFile->findNext(array(T_SEMICOLON, T_CLOSE_TAG), $stackPtr, null, false);
68
69        // If the token before the semi-colon is not a closing parenthesis, then we are not concerned.
70        $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($end - 1), null, true);
71        if ($tokens[$prev]['code'] !== T_CLOSE_PARENTHESIS) {
72            $phpcsFile->recordMetric($stackPtr, 'Brackets around echoed strings', 'no');
73            return;
74        }
75
76        // If the parenthesis don't match, then we are not concerned.
77        if ($tokens[$firstContent]['parenthesis_closer'] !== $prev) {
78            $phpcsFile->recordMetric($stackPtr, 'Brackets around echoed strings', 'no');
79            return;
80        }
81
82        $phpcsFile->recordMetric($stackPtr, 'Brackets around echoed strings', 'yes');
83
84        if (($phpcsFile->findNext(PHP_CodeSniffer_Tokens::$operators, $stackPtr, $end, false)) === false) {
85            // There are no arithmetic operators in this.
86            $error = 'Echoed strings should not be bracketed';
87            $fix   = $phpcsFile->addFixableError($error, $stackPtr, 'HasBracket');
88            if ($fix === true) {
89                $phpcsFile->fixer->beginChangeset();
90                $phpcsFile->fixer->replaceToken($firstContent, '');
91                if ($tokens[($firstContent - 1)]['code'] !== T_WHITESPACE) {
92                    $phpcsFile->fixer->addContent(($firstContent - 1), ' ');
93                }
94
95                $phpcsFile->fixer->replaceToken($prev, '');
96                $phpcsFile->fixer->endChangeset();
97            }
98        }
99
100    }//end process()
101
102
103}//end class
104