1<?php 2/** 3 * Generic_Sniffs_NamingConventions_ConstructorNameSniff. 4 * 5 * PHP version 5 6 * 7 * @category PHP 8 * @package PHP_CodeSniffer 9 * @author Greg Sherwood <gsherwood@squiz.net> 10 * @author Leif Wickland <lwickland@rightnow.com> 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 16if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { 17 $error = 'Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'; 18 throw new PHP_CodeSniffer_Exception($error); 19} 20 21/** 22 * Generic_Sniffs_NamingConventions_ConstructorNameSniff. 23 * 24 * Favor PHP 5 constructor syntax, which uses "function __construct()". 25 * Avoid PHP 4 constructor syntax, which uses "function ClassName()". 26 * 27 * @category PHP 28 * @package PHP_CodeSniffer 29 * @author Leif Wickland <lwickland@rightnow.com> 30 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 31 * @version Release: @package_version@ 32 * @link http://pear.php.net/package/PHP_CodeSniffer 33 */ 34class Generic_Sniffs_NamingConventions_ConstructorNameSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff 35{ 36 37 /** 38 * The name of the class we are currently checking. 39 * 40 * @var string 41 */ 42 private $_currentClass = ''; 43 44 /** 45 * A list of functions in the current class. 46 * 47 * @var string[] 48 */ 49 private $_functionList = array(); 50 51 52 /** 53 * Constructs the test with the tokens it wishes to listen for. 54 */ 55 public function __construct() 56 { 57 parent::__construct(array(T_CLASS, T_ANON_CLASS, T_INTERFACE), array(T_FUNCTION), true); 58 59 }//end __construct() 60 61 62 /** 63 * Processes this test when one of its tokens is encountered. 64 * 65 * @param PHP_CodeSniffer_File $phpcsFile The current file being scanned. 66 * @param int $stackPtr The position of the current token 67 * in the stack passed in $tokens. 68 * @param int $currScope A pointer to the start of the scope. 69 * 70 * @return void 71 */ 72 protected function processTokenWithinScope( 73 PHP_CodeSniffer_File $phpcsFile, 74 $stackPtr, 75 $currScope 76 ) { 77 $className = $phpcsFile->getDeclarationName($currScope); 78 if ($className !== $this->_currentClass) { 79 $this->loadFunctionNamesInScope($phpcsFile, $currScope); 80 $this->_currentClass = $className; 81 } 82 83 $methodName = $phpcsFile->getDeclarationName($stackPtr); 84 85 if (strcasecmp($methodName, $className) === 0) { 86 if (in_array('__construct', $this->_functionList) === false) { 87 $error = 'PHP4 style constructors are not allowed; use "__construct()" instead'; 88 $phpcsFile->addError($error, $stackPtr, 'OldStyle'); 89 } 90 } else if (strcasecmp($methodName, '__construct') !== 0) { 91 // Not a constructor. 92 return; 93 } 94 95 $tokens = $phpcsFile->getTokens(); 96 97 $parentClassName = $phpcsFile->findExtendedClassName($currScope); 98 if ($parentClassName === false) { 99 return; 100 } 101 102 // Stop if the constructor doesn't have a body, like when it is abstract. 103 if (isset($tokens[$stackPtr]['scope_closer']) === false) { 104 return; 105 } 106 107 $endFunctionIndex = $tokens[$stackPtr]['scope_closer']; 108 $startIndex = $stackPtr; 109 while (($doubleColonIndex = $phpcsFile->findNext(T_DOUBLE_COLON, $startIndex, $endFunctionIndex)) !== false) { 110 if ($tokens[($doubleColonIndex + 1)]['code'] === T_STRING 111 && $tokens[($doubleColonIndex + 1)]['content'] === $parentClassName 112 ) { 113 $error = 'PHP4 style calls to parent constructors are not allowed; use "parent::__construct()" instead'; 114 $phpcsFile->addError($error, ($doubleColonIndex + 1), 'OldStyleCall'); 115 } 116 117 $startIndex = ($doubleColonIndex + 1); 118 } 119 120 }//end processTokenWithinScope() 121 122 123 /** 124 * Extracts all the function names found in the given scope. 125 * 126 * @param PHP_CodeSniffer_File $phpcsFile The current file being scanned. 127 * @param int $currScope A pointer to the start of the scope. 128 * 129 * @return void 130 */ 131 protected function loadFunctionNamesInScope(PHP_CodeSniffer_File $phpcsFile, $currScope) 132 { 133 $this->_functionList = array(); 134 $tokens = $phpcsFile->getTokens(); 135 136 for ($i = ($tokens[$currScope]['scope_opener'] + 1); $i < $tokens[$currScope]['scope_closer']; $i++) { 137 if ($tokens[$i]['code'] !== T_FUNCTION) { 138 continue; 139 } 140 141 $next = $phpcsFile->findNext(T_STRING, $i); 142 $this->_functionList[] = trim($tokens[$next]['content']); 143 } 144 145 }//end loadFunctionNamesInScope() 146 147 148}//end class 149