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

Documentation generated on Mon, 11 Mar 2019 14:23:30 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.