/src/Sniffs/NamingConventions/ValidMethodNameSniff.php

https://github.com/p4ul/CodeIgniter-for-PHP_CodeSniffer · PHP · 161 lines · 84 code · 18 blank · 59 comment · 16 complexity · 759f3cb00827cf414a1eb35eca1b44fb MD5 · raw file

  1. <?php
  2. /**
  3. * CodeIgniter_Sniffs_NamingConventions_ValidMethodNameSniff.
  4. *
  5. * PHP version 5
  6. *
  7. * @category PHP
  8. * @package PHP_CodeSniffer
  9. * @author Thomas Ernest <thomas.ernest@baoabz.com>
  10. * @copyright 2010 Thomas Ernest
  11. * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
  12. * @link http://pear.php.net/package/PHP_CodeSniffer
  13. */
  14. if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) {
  15. $error = 'Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found';
  16. throw new PHP_CodeSniffer_Exception($error);
  17. }
  18. /**
  19. * CodeIgniter_Sniffs_NamingConventions_ValidMethodNameSniff.
  20. *
  21. * Ensures that class methods and functions areentirely lowercased and that
  22. * words are separated with an underscore, and not CamelCased.
  23. * Ensures that private class methods are prefixed with an underscore and that
  24. * all other methods are not prefixed with an underscored.
  25. * Ensures that names longer than 50 chars are prohibited. Likewise names longer
  26. * than 35 chars raise a warning.
  27. *
  28. * @todo Use a rule property or a configuration variable to allow users to set
  29. * their own maximum lengths for function and method names. Have a look at
  30. * CodeIgniter_Sniffs_Files_ClosingLocationCommentSniff and application root.
  31. *
  32. * @category PHP
  33. * @package PHP_CodeSniffer
  34. * @author Thomas Ernest <thomas.ernest@baoabz.com>
  35. * @copyright 2010 Thomas Ernest
  36. * @license http://thomas.ernest.fr/developement/php_cs/licence GNU General Public License
  37. * @link http://pear.php.net/package/PHP_CodeSniffer
  38. */
  39. class CodeIgniter_Sniffs_NamingConventions_ValidMethodNameSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff
  40. {
  41. /**
  42. * A list of all PHP magic methods.
  43. *
  44. * @var array
  45. */
  46. protected static $magicMethods = array(
  47. 'construct',
  48. 'destruct',
  49. 'call',
  50. 'callStatic',
  51. 'get',
  52. 'set',
  53. 'isset',
  54. 'unset',
  55. 'sleep',
  56. 'wakeup',
  57. 'toString',
  58. 'set_state',
  59. 'clone',
  60. );
  61. /**
  62. * Defines which token(s) in which scope(s) will be proceed.
  63. */
  64. public function __construct()
  65. {
  66. parent::__construct(array(T_CLASS, T_INTERFACE), array(T_FUNCTION), true);
  67. }//end __construct()
  68. /**
  69. * Processes the tokens within the scope.
  70. *
  71. * @param PHP_CodeSniffer_File $phpcsFile The file being processed.
  72. * @param int $stackPtr The position where this token was
  73. * found.
  74. * @param int $currScope The position of the current scope.
  75. *
  76. * @return void
  77. */
  78. protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope)
  79. {
  80. $methodName = $phpcsFile->getDeclarationName($stackPtr);
  81. if ($methodName === null) {
  82. // Ignore closures.
  83. return;
  84. }
  85. $className = $phpcsFile->getDeclarationName($currScope);
  86. // Is this a magic method i.e. is prefixed with "__".
  87. if (0 === strcmp(substr($methodName, 0, 2), '__')) {
  88. $magicPart = substr($methodName, 2);
  89. if (in_array($magicPart, self::$magicMethods) === false) {
  90. $error = "Method name \"$className::$methodName\" is invalid; only PHP magic methods should be prefixed with a double underscore";
  91. $phpcsFile->addError($error, $stackPtr);
  92. }
  93. return;
  94. }
  95. // PHP4 constructors are allowed to break our rules.
  96. if ($methodName === $className) {
  97. return;
  98. }
  99. // PHP4 destructors are allowed to break our rules.
  100. if ($methodName === '_'.$className) {
  101. return;
  102. }
  103. if (0 !== strcmp($methodName, strtolower($methodName))) {
  104. $uscrdMethodName = preg_replace('/([A-Z])/', '_${1}', $methodName);
  105. $expectedMethodName = strtolower($uscrdMethodName);
  106. $error = "Class methods should be entirely lowercased. Please consider \"$expectedMethodName\" instead of \"$methodName\".";
  107. $phpcsFile->addError($error, $stackPtr);
  108. return;
  109. }
  110. $methodProps = $phpcsFile->getMethodProperties($stackPtr);
  111. $scope = $methodProps['scope'];
  112. $scopeSpecified = $methodProps['scope_specified'];
  113. // If it's a private method, it must have an underscore on the front.
  114. if ($scope === 'private' && $methodName{0} !== '_') {
  115. $error = "Private method name \"$className::$methodName\" must be prefixed with an underscore";
  116. $phpcsFile->addError($error, $stackPtr);
  117. return;
  118. }
  119. // If it's not a private method, it must not have an underscore on the front.
  120. if ($scope !== 'private' && $methodName{0} === '_') {
  121. if (true === $scopeSpecified) {
  122. $error = "Public method name \"$className::$methodName\" must not be prefixed with an underscore";
  123. } else {
  124. $error = ucfirst($scope)." method name \"$className::$methodName\" must not be prefixed with an underscore";
  125. }
  126. $phpcsFile->addError($error, $stackPtr);
  127. return;
  128. }
  129. // If name is too verbose,
  130. // then either an error or a warning is displayed.
  131. $error_limit = 50;
  132. $warning_limit = 35;
  133. if (strlen($methodName) > $error_limit) {
  134. $error = "Overly long and verbose names are prohibited. Please find a name shorter than $error_limit chars.";
  135. $phpcsFile->addError($error, $stackPtr);
  136. return;
  137. } else if (strlen($methodName) > $warning_limit) {
  138. $warning = "Try to avoid overly long and verbose names in finding a name shorter than $warning_limit chars.";
  139. $phpcsFile->addWarning($warning, $stackPtr);
  140. }
  141. }//end processTokenWithinScope()
  142. }//end class
  143. ?>