PHP_CodeSniffer
[ class tree: PHP_CodeSniffer ] [ index: PHP_CodeSniffer ] [ all elements ]

Source for file ValidFunctionNameSniff.php

Documentation is available at ValidFunctionNameSniff.php

  1. <?php
  2. /**
  3.  * Ensures method and function names are correct.
  4.  *
  5.  * @author    Greg Sherwood <gsherwood@squiz.net>
  6.  * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
  7.  * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
  8.  */
  9.  
  10. namespace PHP_CodeSniffer\Standards\PEAR\Sniffs\NamingConventions;
  11.  
  12. use PHP_CodeSniffer\Sniffs\AbstractScopeSniff;
  13. use PHP_CodeSniffer\Util\Common;
  14. use PHP_CodeSniffer\Util\Tokens;
  15. use PHP_CodeSniffer\Files\File;
  16.  
  17. class ValidFunctionNameSniff extends AbstractScopeSniff
  18. {
  19.  
  20.     /**
  21.      * A list of all PHP magic methods.
  22.      *
  23.      * @var array 
  24.      */
  25.     protected $magicMethods = array(
  26.                                'construct'  => true,
  27.                                'destruct'   => true,
  28.                                'call'       => true,
  29.                                'callstatic' => true,
  30.                                'get'        => true,
  31.                                'set'        => true,
  32.                                'isset'      => true,
  33.                                'unset'      => true,
  34.                                'sleep'      => true,
  35.                                'wakeup'     => true,
  36.                                'tostring'   => true,
  37.                                'set_state'  => true,
  38.                                'clone'      => true,
  39.                                'invoke'     => true,
  40.                                'debuginfo'  => true,
  41.                               );
  42.  
  43.     /**
  44.      * A list of all PHP magic functions.
  45.      *
  46.      * @var array 
  47.      */
  48.     protected $magicFunctions = array('autoload' => true);
  49.  
  50.  
  51.     /**
  52.      * Constructs a PEAR_Sniffs_NamingConventions_ValidFunctionNameSniff.
  53.      */
  54.     public function __construct()
  55.     {
  56.         parent::__construct(Tokens::$ooScopeTokensarray(T_FUNCTION)true);
  57.  
  58.     }//end __construct()
  59.  
  60.  
  61.     /**
  62.      * Processes the tokens within the scope.
  63.      *
  64.      * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being processed.
  65.      * @param int                         $stackPtr  The position where this token was
  66.      *                                                found.
  67.      * @param int                         $currScope The position of the current scope.
  68.      *
  69.      * @return void 
  70.      */
  71.     protected function processTokenWithinScope(File $phpcsFile$stackPtr$currScope)
  72.     {
  73.         $methodName $phpcsFile->getDeclarationName($stackPtr);
  74.         if ($methodName === null{
  75.             // Ignore closures.
  76.             return;
  77.         }
  78.  
  79.         $className $phpcsFile->getDeclarationName($currScope);
  80.         $errorData = array($className.'::'.$methodName);
  81.  
  82.         // Is this a magic method. i.e., is prefixed with "__" ?
  83.         if (preg_match('|^__[^_]|'$methodName!== 0{
  84.             $magicPart strtolower(substr($methodName2));
  85.             if (isset($this->magicMethods[$magicPart]=== false{
  86.                  $error 'Method name "%s" is invalid; only PHP magic methods should be prefixed with a double underscore';
  87.                  $phpcsFile->addError($error$stackPtr'MethodDoubleUnderscore'$errorData);
  88.             }
  89.  
  90.             return;
  91.         }
  92.  
  93.         // PHP4 constructors are allowed to break our rules.
  94.         if ($methodName === $className{
  95.             return;
  96.         }
  97.  
  98.         // PHP4 destructors are allowed to break our rules.
  99.         if ($methodName === '_'.$className{
  100.             return;
  101.         }
  102.  
  103.         $methodProps    $phpcsFile->getMethodProperties($stackPtr);
  104.         $scope          $methodProps['scope'];
  105.         $scopeSpecified $methodProps['scope_specified'];
  106.  
  107.         if ($methodProps['scope'=== 'private'{
  108.             $isPublic = false;
  109.         else {
  110.             $isPublic = true;
  111.         }
  112.  
  113.         // If it's a private method, it must have an underscore on the front.
  114.         if ($isPublic === false{
  115.             if ($methodName{0!== '_'{
  116.                 $error 'Private method name "%s" must be prefixed with an underscore';
  117.                 $phpcsFile->addError($error$stackPtr'PrivateNoUnderscore'$errorData);
  118.                 $phpcsFile->recordMetric($stackPtr'Private method prefixed with underscore''no');
  119.                 return;
  120.             else {
  121.                 $phpcsFile->recordMetric($stackPtr'Private method prefixed with underscore''yes');
  122.             }
  123.         }
  124.  
  125.         // If it's not a private method, it must not have an underscore on the front.
  126.         if ($isPublic === true && $scopeSpecified === true && $methodName{0=== '_'{
  127.             $error '%s method name "%s" must not be prefixed with an underscore';
  128.             $data  = array(
  129.                       ucfirst($scope),
  130.                       $errorData[0],
  131.                      );
  132.             $phpcsFile->addError($error$stackPtr'PublicUnderscore'$data);
  133.             return;
  134.         }
  135.  
  136.         // If the scope was specified on the method, then the method must be
  137.         // camel caps and an underscore should be checked for. If it wasn't
  138.         // specified, treat it like a public method and remove the underscore
  139.         // prefix if there is one because we cant determine if it is private or
  140.         // public.
  141.         $testMethodName $methodName;
  142.         if ($scopeSpecified === false && $methodName{0=== '_'{
  143.             $testMethodName substr($methodName1);
  144.         }
  145.  
  146.         if (Common::isCamelCaps($testMethodNamefalse$isPublicfalse=== false{
  147.             if ($scopeSpecified === true{
  148.                 $error '%s method name "%s" is not in camel caps format';
  149.                 $data  = array(
  150.                           ucfirst($scope),
  151.                           $errorData[0],
  152.                          );
  153.                 $phpcsFile->addError($error$stackPtr'ScopeNotCamelCaps'$data);
  154.             else {
  155.                 $error 'Method name "%s" is not in camel caps format';
  156.                 $phpcsFile->addError($error$stackPtr'NotCamelCaps'$errorData);
  157.             }
  158.  
  159.             return;
  160.         }
  161.  
  162.     }//end processTokenWithinScope()
  163.  
  164.  
  165.     /**
  166.      * Processes the tokens outside the scope.
  167.      *
  168.      * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being processed.
  169.      * @param int                         $stackPtr  The position where this token was
  170.      *                                                found.
  171.      *
  172.      * @return void 
  173.      */
  174.     protected function processTokenOutsideScope(File $phpcsFile$stackPtr)
  175.     {
  176.         $functionName $phpcsFile->getDeclarationName($stackPtr);
  177.         if ($functionName === null{
  178.             // Ignore closures.
  179.             return;
  180.         }
  181.  
  182.         if (ltrim($functionName'_'=== ''{
  183.             // Ignore special functions.
  184.             return;
  185.         }
  186.  
  187.         $errorData = array($functionName);
  188.  
  189.         // Is this a magic function. i.e., it is prefixed with "__".
  190.         if (preg_match('|^__[^_]|'$functionName!== 0{
  191.             $magicPart strtolower(substr($functionName2));
  192.             if (isset($this->magicFunctions[$magicPart]=== false{
  193.                  $error 'Function name "%s" is invalid; only PHP magic methods should be prefixed with a double underscore';
  194.                  $phpcsFile->addError($error$stackPtr'FunctionDoubleUnderscore'$errorData);
  195.             }
  196.  
  197.             return;
  198.         }
  199.  
  200.         // Function names can be in two parts; the package name and
  201.         // the function name.
  202.         $packagePart   '';
  203.         $camelCapsPart '';
  204.         $underscorePos strrpos($functionName'_');
  205.         if ($underscorePos === false{
  206.             $camelCapsPart $functionName;
  207.         else {
  208.             $packagePart   substr($functionName0$underscorePos);
  209.             $camelCapsPart substr($functionName($underscorePos + 1));
  210.  
  211.             // We don't care about _'s on the front.
  212.             $packagePart ltrim($packagePart'_');
  213.         }
  214.  
  215.         // If it has a package part, make sure the first letter is a capital.
  216.         if ($packagePart !== ''{
  217.             if ($functionName{0=== '_'{
  218.                 $error 'Function name "%s" is invalid; only private methods should be prefixed with an underscore';
  219.                 $phpcsFile->addError($error$stackPtr'FunctionUnderscore'$errorData);
  220.                 return;
  221.             }
  222.  
  223.             if ($functionName{0!== strtoupper($functionName{0})) {
  224.                 $error 'Function name "%s" is prefixed with a package name but does not begin with a capital letter';
  225.                 $phpcsFile->addError($error$stackPtr'FunctionNoCapital'$errorData);
  226.                 return;
  227.             }
  228.         }
  229.  
  230.         // If it doesn't have a camel caps part, it's not valid.
  231.         if (trim($camelCapsPart=== ''{
  232.             $error 'Function name "%s" is not valid; name appears incomplete';
  233.             $phpcsFile->addError($error$stackPtr'FunctionInvalid'$errorData);
  234.             return;
  235.         }
  236.  
  237.         $validName        = true;
  238.         $newPackagePart   $packagePart;
  239.         $newCamelCapsPart $camelCapsPart;
  240.  
  241.         // Every function must have a camel caps part, so check that first.
  242.         if (Common::isCamelCaps($camelCapsPartfalsetruefalse=== false{
  243.             $validName        = false;
  244.             $newCamelCapsPart strtolower($camelCapsPart{0}).substr($camelCapsPart1);
  245.         }
  246.  
  247.         if ($packagePart !== ''{
  248.             // Check that each new word starts with a capital.
  249.             $nameBits explode('_'$packagePart);
  250.             foreach ($nameBits as $bit{
  251.                 if ($bit{0!== strtoupper($bit{0})) {
  252.                     $newPackagePart '';
  253.                     foreach ($nameBits as $bit{
  254.                         $newPackagePart .= strtoupper($bit{0}).substr($bit1).'_';
  255.                     }
  256.  
  257.                     $validName = false;
  258.                     break;
  259.                 }
  260.             }
  261.         }
  262.  
  263.         if ($validName === false{
  264.             $newName rtrim($newPackagePart'_').'_'.$newCamelCapsPart;
  265.             if ($newPackagePart === ''{
  266.                 $newName $newCamelCapsPart;
  267.             else {
  268.                 $newName rtrim($newPackagePart'_').'_'.$newCamelCapsPart;
  269.             }
  270.  
  271.             $error  'Function name "%s" is invalid; consider "%s" instead';
  272.             $data   $errorData;
  273.             $data[$newName;
  274.             $phpcsFile->addError($error$stackPtr'FunctionNameInvalid'$data);
  275.         }
  276.  
  277.     }//end processTokenOutsideScope()
  278.  
  279.  
  280. }//end class

Documentation generated on Mon, 11 Mar 2019 15:27:51 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.