PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/squizlabs/php_codesniffer/CodeSniffer/Standards/PSR2/Sniffs/Classes/ClassDeclarationSniff.php

https://gitlab.com/yousafsyed/easternglamor
PHP | 332 lines | 222 code | 36 blank | 74 comment | 49 complexity | 9b4deb2d7330e6898c295d5c1a246ec8 MD5 | raw file
  1. <?php
  2. /**
  3. * Class Declaration Test.
  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. if (class_exists('PEAR_Sniffs_Classes_ClassDeclarationSniff', true) === false) {
  15. $error = 'Class PEAR_Sniffs_Classes_ClassDeclarationSniff not found';
  16. throw new PHP_CodeSniffer_Exception($error);
  17. }
  18. /**
  19. * Class Declaration Test.
  20. *
  21. * Checks the declaration of the class and its inheritance is correct.
  22. *
  23. * @category PHP
  24. * @package PHP_CodeSniffer
  25. * @author Greg Sherwood <gsherwood@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. */
  31. class PSR2_Sniffs_Classes_ClassDeclarationSniff extends PEAR_Sniffs_Classes_ClassDeclarationSniff
  32. {
  33. /**
  34. * Processes this test, when one of its tokens is encountered.
  35. *
  36. * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
  37. * @param int $stackPtr The position of the current token
  38. * in the stack passed in $tokens.
  39. *
  40. * @return void
  41. */
  42. public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
  43. {
  44. // We want all the errors from the PEAR standard, plus some of our own.
  45. parent::process($phpcsFile, $stackPtr);
  46. $this->processOpen($phpcsFile, $stackPtr);
  47. $this->processClose($phpcsFile, $stackPtr);
  48. }//end process()
  49. /**
  50. * Processes the opening section of a class declaration.
  51. *
  52. * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
  53. * @param int $stackPtr The position of the current token
  54. * in the stack passed in $tokens.
  55. *
  56. * @return void
  57. */
  58. public function processOpen(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
  59. {
  60. $tokens = $phpcsFile->getTokens();
  61. // Check alignment of the keyword and braces.
  62. if ($tokens[($stackPtr - 1)]['code'] === T_WHITESPACE) {
  63. $prevContent = $tokens[($stackPtr - 1)]['content'];
  64. if ($prevContent !== $phpcsFile->eolChar) {
  65. $blankSpace = substr($prevContent, strpos($prevContent, $phpcsFile->eolChar));
  66. $spaces = strlen($blankSpace);
  67. if (in_array($tokens[($stackPtr - 2)]['code'], array(T_ABSTRACT, T_FINAL)) === true
  68. && $spaces !== 1
  69. ) {
  70. $type = strtolower($tokens[$stackPtr]['content']);
  71. $prevContent = strtolower($tokens[($stackPtr - 2)]['content']);
  72. $error = 'Expected 1 space between %s and %s keywords; %s found';
  73. $data = array(
  74. $prevContent,
  75. $type,
  76. $spaces,
  77. );
  78. $phpcsFile->addError($error, $stackPtr, 'SpaceBeforeKeyword', $data);
  79. }
  80. }
  81. }//end if
  82. // We'll need the indent of the class/interface declaration for later.
  83. $classIndent = 0;
  84. for ($i = ($stackPtr - 1); $i > 0; $i--) {
  85. if ($tokens[$i]['line'] === $tokens[$stackPtr]['line']) {
  86. continue;
  87. }
  88. // We changed lines.
  89. if ($tokens[($i + 1)]['code'] === T_WHITESPACE) {
  90. $classIndent = strlen($tokens[($i + 1)]['content']);
  91. }
  92. break;
  93. }
  94. $keyword = $stackPtr;
  95. $openingBrace = $tokens[$stackPtr]['scope_opener'];
  96. $className = $phpcsFile->findNext(T_STRING, $stackPtr);
  97. $classOrInterface = strtolower($tokens[$keyword]['content']);
  98. // Spacing of the keyword.
  99. $gap = $tokens[($stackPtr + 1)]['content'];
  100. if (strlen($gap) !== 1) {
  101. $found = strlen($gap);
  102. $error = 'Expected 1 space between %s keyword and %s name; %s found';
  103. $data = array(
  104. $classOrInterface,
  105. $classOrInterface,
  106. $found,
  107. );
  108. $phpcsFile->addError($error, $stackPtr, 'SpaceAfterKeyword', $data);
  109. }
  110. // Check after the class/interface name.
  111. $gap = $tokens[($className + 1)]['content'];
  112. if (strlen($gap) !== 1) {
  113. $found = strlen($gap);
  114. $error = 'Expected 1 space after %s name; %s found';
  115. $data = array(
  116. $classOrInterface,
  117. $found,
  118. );
  119. $phpcsFile->addError($error, $stackPtr, 'SpaceAfterName', $data);
  120. }
  121. // Check positions of the extends and implements keywords.
  122. foreach (array('extends', 'implements') as $keywordType) {
  123. $keyword = $phpcsFile->findNext(constant('T_'.strtoupper($keywordType)), ($stackPtr + 1), $openingBrace);
  124. if ($keyword !== false) {
  125. if ($tokens[$keyword]['line'] !== $tokens[$stackPtr]['line']) {
  126. $error = 'The '.$keywordType.' keyword must be on the same line as the %s name';
  127. $data = array($classOrInterface);
  128. $phpcsFile->addError($error, $keyword, ucfirst($keywordType).'Line', $data);
  129. } else {
  130. // Check the whitespace before. Whitespace after is checked
  131. // later by looking at the whitespace before the first class name
  132. // in the list.
  133. $gap = strlen($tokens[($keyword - 1)]['content']);
  134. if ($gap !== 1) {
  135. $error = 'Expected 1 space before '.$keywordType.' keyword; %s found';
  136. $data = array($gap);
  137. $phpcsFile->addError($error, $keyword, 'SpaceBefore'.ucfirst($keywordType), $data);
  138. }
  139. }
  140. }
  141. }//end foreach
  142. // Check each of the extends/implements class names. If the extends/implements
  143. // keyword is the last content on the line, it means we need to check for
  144. // the multi-line format, so we do not include the class names
  145. // from the extends/implements list in the following check.
  146. // Note that classes can only extend one other class, so they can use a
  147. // multi-line implements format, whereas an interface can extend multiple
  148. // other interfaces, and so uses a multi-line extends format.
  149. if ($tokens[$stackPtr]['code'] === T_INTERFACE) {
  150. $keywordTokenType = T_EXTENDS;
  151. } else {
  152. $keywordTokenType = T_IMPLEMENTS;
  153. }
  154. $implements = $phpcsFile->findNext($keywordTokenType, ($stackPtr + 1), $openingBrace);
  155. $multiLineImplements = false;
  156. if ($implements !== false) {
  157. $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($implements + 1), $openingBrace, true);
  158. if ($tokens[$next]['line'] > $tokens[$implements]['line']) {
  159. $multiLineImplements = true;
  160. }
  161. }
  162. $find = array(
  163. T_STRING,
  164. $keywordTokenType,
  165. );
  166. $classNames = array();
  167. $nextClass = $phpcsFile->findNext($find, ($className + 2), ($openingBrace - 1));
  168. while ($nextClass !== false) {
  169. $classNames[] = $nextClass;
  170. $nextClass = $phpcsFile->findNext($find, ($nextClass + 1), ($openingBrace - 1));
  171. }
  172. $classCount = count($classNames);
  173. $checkingImplements = false;
  174. foreach ($classNames as $i => $className) {
  175. if ($tokens[$className]['code'] == $keywordTokenType) {
  176. $checkingImplements = true;
  177. continue;
  178. }
  179. if ($checkingImplements === true
  180. && $multiLineImplements === true
  181. && ($tokens[($className - 1)]['code'] !== T_NS_SEPARATOR
  182. || $tokens[($className - 2)]['code'] !== T_STRING)
  183. ) {
  184. $prev = $phpcsFile->findPrevious(
  185. array(
  186. T_NS_SEPARATOR,
  187. T_WHITESPACE,
  188. ),
  189. ($className - 1),
  190. $implements,
  191. true
  192. );
  193. if ($tokens[$prev]['line'] !== ($tokens[$className]['line'] - 1)) {
  194. if ($keywordTokenType === T_EXTENDS) {
  195. $error = 'Only one interface may be specified per line in a multi-line extends declaration';
  196. $phpcsFile->addError($error, $className, 'ExtendsInterfaceSameLine');
  197. } else {
  198. $error = 'Only one interface may be specified per line in a multi-line implements declaration';
  199. $phpcsFile->addError($error, $className, 'InterfaceSameLine');
  200. }
  201. } else {
  202. $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($className - 1), $implements);
  203. $found = strlen($tokens[$prev]['content']);
  204. $expected = ($classIndent + $this->indent);
  205. if ($found !== $expected) {
  206. $error = 'Expected %s spaces before interface name; %s found';
  207. $data = array(
  208. $expected,
  209. $found,
  210. );
  211. $phpcsFile->addError($error, $className, 'InterfaceWrongIndent', $data);
  212. }
  213. }//end if
  214. } else if ($tokens[($className - 1)]['code'] !== T_NS_SEPARATOR
  215. || $tokens[($className - 2)]['code'] !== T_STRING
  216. ) {
  217. if ($tokens[($className - 1)]['code'] === T_COMMA
  218. || ($tokens[($className - 1)]['code'] === T_NS_SEPARATOR
  219. && $tokens[($className - 2)]['code'] === T_COMMA)
  220. ) {
  221. $error = 'Expected 1 space before "%s"; 0 found';
  222. $data = array($tokens[$className]['content']);
  223. $phpcsFile->addError($error, ($nextComma + 1), 'NoSpaceBeforeName', $data);
  224. } else {
  225. if ($tokens[($className - 1)]['code'] === T_NS_SEPARATOR) {
  226. $spaceBefore = strlen($tokens[($className - 2)]['content']);
  227. } else {
  228. $spaceBefore = strlen($tokens[($className - 1)]['content']);
  229. }
  230. if ($spaceBefore !== 1) {
  231. $error = 'Expected 1 space before "%s"; %s found';
  232. $data = array(
  233. $tokens[$className]['content'],
  234. $spaceBefore,
  235. );
  236. $phpcsFile->addError($error, $className, 'SpaceBeforeName', $data);
  237. }
  238. }//end if
  239. }//end if
  240. if ($tokens[($className + 1)]['code'] !== T_NS_SEPARATOR
  241. && $tokens[($className + 1)]['code'] !== T_COMMA
  242. ) {
  243. if ($i !== ($classCount - 1)) {
  244. // This is not the last class name, and the comma
  245. // is not where we expect it to be.
  246. if ($tokens[($className + 2)]['code'] !== $keywordTokenType) {
  247. $error = 'Expected 0 spaces between "%s" and comma; %s found';
  248. $data = array(
  249. $tokens[$className]['content'],
  250. strlen($tokens[($className + 1)]['content']),
  251. );
  252. $phpcsFile->addError($error, $className, 'SpaceBeforeComma', $data);
  253. }
  254. }
  255. $nextComma = $phpcsFile->findNext(T_COMMA, $className);
  256. } else {
  257. $nextComma = ($className + 1);
  258. }
  259. }//end foreach
  260. }//end processOpen()
  261. /**
  262. * Processes the closing section of a class declaration.
  263. *
  264. * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
  265. * @param int $stackPtr The position of the current token
  266. * in the stack passed in $tokens.
  267. *
  268. * @return void
  269. */
  270. public function processClose(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
  271. {
  272. $tokens = $phpcsFile->getTokens();
  273. // Check that the closing brace comes right after the code body.
  274. $closeBrace = $tokens[$stackPtr]['scope_closer'];
  275. $prevContent = $phpcsFile->findPrevious(T_WHITESPACE, ($closeBrace - 1), null, true);
  276. if ($prevContent !== $tokens[$stackPtr]['scope_opener']
  277. && $tokens[$prevContent]['line'] !== ($tokens[$closeBrace]['line'] - 1)
  278. ) {
  279. $error = 'The closing brace for the %s must go on the next line after the body';
  280. $data = array($tokens[$stackPtr]['content']);
  281. $phpcsFile->addError($error, $closeBrace, 'CloseBraceAfterBody', $data);
  282. }
  283. // Check the closing brace is on it's own line, but allow
  284. // for comments like "//end class".
  285. $nextContent = $phpcsFile->findNext(T_COMMENT, ($closeBrace + 1), null, true);
  286. if ($tokens[$nextContent]['content'] !== $phpcsFile->eolChar
  287. && $tokens[$nextContent]['line'] === $tokens[$closeBrace]['line']
  288. ) {
  289. $type = strtolower($tokens[$stackPtr]['content']);
  290. $error = 'Closing %s brace must be on a line by itself';
  291. $data = array($tokens[$stackPtr]['content']);
  292. $phpcsFile->addError($error, $closeBrace, 'CloseBraceSameLine', $data);
  293. }
  294. }//end processClose()
  295. }//end class
  296. ?>