1<?php 2/** 3 * PSR2_Sniffs_Methods_MethodDeclarationSniff. 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 15if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { 16 throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'); 17} 18 19/** 20 * PSR2_Sniffs_Methods_MethodDeclarationSniff. 21 * 22 * Checks that the method declaration is correct. 23 * 24 * @category PHP 25 * @package PHP_CodeSniffer 26 * @author Greg Sherwood <gsherwood@squiz.net> 27 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600) 28 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 29 * @version Release: @package_version@ 30 * @link http://pear.php.net/package/PHP_CodeSniffer 31 */ 32class PSR2_Sniffs_Methods_MethodDeclarationSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff 33{ 34 35 36 /** 37 * Constructs a Squiz_Sniffs_Scope_MethodScopeSniff. 38 */ 39 public function __construct() 40 { 41 parent::__construct(array(T_CLASS, T_INTERFACE), array(T_FUNCTION)); 42 43 }//end __construct() 44 45 46 /** 47 * Processes the function tokens within the class. 48 * 49 * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. 50 * @param int $stackPtr The position where the token was found. 51 * @param int $currScope The current scope opener token. 52 * 53 * @return void 54 */ 55 protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope) 56 { 57 $tokens = $phpcsFile->getTokens(); 58 59 $methodName = $phpcsFile->getDeclarationName($stackPtr); 60 if ($methodName === null) { 61 // Ignore closures. 62 return; 63 } 64 65 if ($methodName[0] === '_' && isset($methodName[1]) === true && $methodName[1] !== '_') { 66 $error = 'Method name "%s" should not be prefixed with an underscore to indicate visibility'; 67 $data = array($methodName); 68 $phpcsFile->addWarning($error, $stackPtr, 'Underscore', $data); 69 } 70 71 $visibility = 0; 72 $static = 0; 73 $abstract = 0; 74 $final = 0; 75 76 $find = PHP_CodeSniffer_Tokens::$methodPrefixes; 77 $find[] = T_WHITESPACE; 78 $prev = $phpcsFile->findPrevious($find, ($stackPtr - 1), null, true); 79 80 $prefix = $stackPtr; 81 while (($prefix = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$methodPrefixes, ($prefix - 1), $prev)) !== false) { 82 switch ($tokens[$prefix]['code']) { 83 case T_STATIC: 84 $static = $prefix; 85 break; 86 case T_ABSTRACT: 87 $abstract = $prefix; 88 break; 89 case T_FINAL: 90 $final = $prefix; 91 break; 92 default: 93 $visibility = $prefix; 94 break; 95 } 96 } 97 98 $fixes = array(); 99 100 if ($visibility !== 0 && $final > $visibility) { 101 $error = 'The final declaration must precede the visibility declaration'; 102 $fix = $phpcsFile->addFixableError($error, $final, 'FinalAfterVisibility'); 103 if ($fix === true) { 104 $fixes[$final] = ''; 105 $fixes[($final + 1)] = ''; 106 if (isset($fixes[$visibility]) === true) { 107 $fixes[$visibility] = 'final '.$fixes[$visibility]; 108 } else { 109 $fixes[$visibility] = 'final '.$tokens[$visibility]['content']; 110 } 111 } 112 } 113 114 if ($visibility !== 0 && $abstract > $visibility) { 115 $error = 'The abstract declaration must precede the visibility declaration'; 116 $fix = $phpcsFile->addFixableError($error, $abstract, 'AbstractAfterVisibility'); 117 if ($fix === true) { 118 $fixes[$abstract] = ''; 119 $fixes[($abstract + 1)] = ''; 120 if (isset($fixes[$visibility]) === true) { 121 $fixes[$visibility] = 'abstract '.$fixes[$visibility]; 122 } else { 123 $fixes[$visibility] = 'abstract '.$tokens[$visibility]['content']; 124 } 125 } 126 } 127 128 if ($static !== 0 && $static < $visibility) { 129 $error = 'The static declaration must come after the visibility declaration'; 130 $fix = $phpcsFile->addFixableError($error, $static, 'StaticBeforeVisibility'); 131 if ($fix === true) { 132 $fixes[$static] = ''; 133 $fixes[($static + 1)] = ''; 134 if (isset($fixes[$visibility]) === true) { 135 $fixes[$visibility] = $fixes[$visibility].' static'; 136 } else { 137 $fixes[$visibility] = $tokens[$visibility]['content'].' static'; 138 } 139 } 140 } 141 142 // Batch all the fixes together to reduce the possibility of conflicts. 143 if (empty($fixes) === false) { 144 $phpcsFile->fixer->beginChangeset(); 145 foreach ($fixes as $stackPtr => $content) { 146 $phpcsFile->fixer->replaceToken($stackPtr, $content); 147 } 148 149 $phpcsFile->fixer->endChangeset(); 150 } 151 152 }//end processTokenWithinScope() 153 154 155}//end class 156