1<?php 2/** 3 * Generic_Sniffs_Strings_UnnecessaryStringConcatSniff. 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 * Generic_Sniffs_Strings_UnnecessaryStringConcatSniff. 17 * 18 * Checks that two strings are not concatenated together; suggests 19 * using one string instead. 20 * 21 * @category PHP 22 * @package PHP_CodeSniffer 23 * @author Greg Sherwood <gsherwood@squiz.net> 24 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600) 25 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 26 * @version Release: @package_version@ 27 * @link http://pear.php.net/package/PHP_CodeSniffer 28 */ 29class Generic_Sniffs_Strings_UnnecessaryStringConcatSniff implements PHP_CodeSniffer_Sniff 30{ 31 32 /** 33 * A list of tokenizers this sniff supports. 34 * 35 * @var array 36 */ 37 public $supportedTokenizers = array( 38 'PHP', 39 'JS', 40 ); 41 42 /** 43 * If true, an error will be thrown; otherwise a warning. 44 * 45 * @var bool 46 */ 47 public $error = true; 48 49 /** 50 * If true, strings concatenated over multiple lines are allowed. 51 * 52 * Useful if you break strings over multiple lines to work 53 * within a max line length. 54 * 55 * @var bool 56 */ 57 public $allowMultiline = false; 58 59 60 /** 61 * Returns an array of tokens this test wants to listen for. 62 * 63 * @return array 64 */ 65 public function register() 66 { 67 return array( 68 T_STRING_CONCAT, 69 T_PLUS, 70 ); 71 72 }//end register() 73 74 75 /** 76 * Processes this sniff, when one of its tokens is encountered. 77 * 78 * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 79 * @param int $stackPtr The position of the current token 80 * in the stack passed in $tokens. 81 * 82 * @return void 83 */ 84 public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 85 { 86 // Work out which type of file this is for. 87 $tokens = $phpcsFile->getTokens(); 88 if ($tokens[$stackPtr]['code'] === T_STRING_CONCAT) { 89 if ($phpcsFile->tokenizerType === 'JS') { 90 return; 91 } 92 } else { 93 if ($phpcsFile->tokenizerType === 'PHP') { 94 return; 95 } 96 } 97 98 $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); 99 $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); 100 if ($prev === false || $next === false) { 101 return; 102 } 103 104 if (isset(PHP_CodeSniffer_Tokens::$stringTokens[$tokens[$prev]['code']]) === true 105 && isset(PHP_CodeSniffer_Tokens::$stringTokens[$tokens[$next]['code']]) === true 106 ) { 107 if ($tokens[$prev]['content'][0] === $tokens[$next]['content'][0]) { 108 // Before we throw an error for PHP, allow strings to be 109 // combined if they would have < and ? next to each other because 110 // this trick is sometimes required in PHP strings. 111 if ($phpcsFile->tokenizerType === 'PHP') { 112 $prevChar = substr($tokens[$prev]['content'], -2, 1); 113 $nextChar = $tokens[$next]['content'][1]; 114 $combined = $prevChar.$nextChar; 115 if ($combined === '?'.'>' || $combined === '<'.'?') { 116 return; 117 } 118 } 119 120 if ($this->allowMultiline === true 121 && $tokens[$prev]['line'] !== $tokens[$next]['line'] 122 ) { 123 return; 124 } 125 126 $error = 'String concat is not required here; use a single string instead'; 127 if ($this->error === true) { 128 $phpcsFile->addError($error, $stackPtr, 'Found'); 129 } else { 130 $phpcsFile->addWarning($error, $stackPtr, 'Found'); 131 } 132 }//end if 133 }//end if 134 135 }//end process() 136 137 138}//end class 139