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

Source for file ForbiddenFunctionsSniff.php

Documentation is available at ForbiddenFunctionsSniff.php

  1. <?php
  2. /**
  3.  * Discourages the use of alias functions.
  4.  *
  5.  * Alias functions are kept in PHP for compatibility
  6.  * with older versions. Can be used to forbid the use of any function.
  7.  *
  8.  * @author    Greg Sherwood <gsherwood@squiz.net>
  9.  * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
  10.  * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
  11.  */
  12.  
  13. namespace PHP_CodeSniffer\Standards\Generic\Sniffs\PHP;
  14.  
  15. use PHP_CodeSniffer\Sniffs\Sniff;
  16. use PHP_CodeSniffer\Files\File;
  17.  
  18. class ForbiddenFunctionsSniff implements Sniff
  19. {
  20.  
  21.     /**
  22.      * A list of forbidden functions with their alternatives.
  23.      *
  24.      * The value is NULL if no alternative exists. IE, the
  25.      * function should just not be used.
  26.      *
  27.      * @var array<string, string|null>
  28.      */
  29.     public $forbiddenFunctions = array(
  30.                                   'sizeof' => 'count',
  31.                                   'delete' => 'unset',
  32.                                  );
  33.  
  34.     /**
  35.      * A cache of forbidden function names, for faster lookups.
  36.      *
  37.      * @var string[] 
  38.      */
  39.     protected $forbiddenFunctionNames = array();
  40.  
  41.     /**
  42.      * If true, forbidden functions will be considered regular expressions.
  43.      *
  44.      * @var boolean 
  45.      */
  46.     protected $patternMatch = false;
  47.  
  48.     /**
  49.      * If true, an error will be thrown; otherwise a warning.
  50.      *
  51.      * @var boolean 
  52.      */
  53.     public $error = true;
  54.  
  55.  
  56.     /**
  57.      * Returns an array of tokens this test wants to listen for.
  58.      *
  59.      * @return array 
  60.      */
  61.     public function register()
  62.     {
  63.         // Everyone has had a chance to figure out what forbidden functions
  64.         // they want to check for, so now we can cache out the list.
  65.         $this->forbiddenFunctionNames array_keys($this->forbiddenFunctions);
  66.  
  67.         if ($this->patternMatch === true{
  68.             foreach ($this->forbiddenFunctionNames as $i => $name{
  69.                 $this->forbiddenFunctionNames[$i'/'.$name.'/i';
  70.             }
  71.  
  72.             return array(T_STRING);
  73.         }
  74.  
  75.         // If we are not pattern matching, we need to work out what
  76.         // tokens to listen for.
  77.         $string '<?php ';
  78.         foreach ($this->forbiddenFunctionNames as $name{
  79.             $string .= $name.'();';
  80.         }
  81.  
  82.         $register = array();
  83.  
  84.         $tokens token_get_all($string);
  85.         array_shift($tokens);
  86.         foreach ($tokens as $token{
  87.             if (is_array($token=== true{
  88.                 $register[$token[0];
  89.             }
  90.         }
  91.  
  92.         return array_unique($register);
  93.  
  94.     }//end register()
  95.  
  96.  
  97.     /**
  98.      * Processes this test, when one of its tokens is encountered.
  99.      *
  100.      * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
  101.      * @param int                  $stackPtr  The position of the current token in
  102.      *                                         the stack passed in $tokens.
  103.      *
  104.      * @return void 
  105.      */
  106.     public function process(File $phpcsFile$stackPtr)
  107.     {
  108.         $tokens $phpcsFile->getTokens();
  109.  
  110.         $ignore = array(
  111.                    T_DOUBLE_COLON    => true,
  112.                    T_OBJECT_OPERATOR => true,
  113.                    T_FUNCTION        => true,
  114.                    T_CONST           => true,
  115.                    T_PUBLIC          => true,
  116.                    T_PRIVATE         => true,
  117.                    T_PROTECTED       => true,
  118.                    T_AS              => true,
  119.                    T_NEW             => true,
  120.                    T_INSTEADOF       => true,
  121.                    T_NS_SEPARATOR    => true,
  122.                    T_IMPLEMENTS      => true,
  123.                   );
  124.  
  125.         $prevToken $phpcsFile->findPrevious(T_WHITESPACE($stackPtr - 1)nulltrue);
  126.  
  127.         // If function call is directly preceded by a NS_SEPARATOR it points to the
  128.         // global namespace, so we should still catch it.
  129.         if ($tokens[$prevToken]['code'=== T_NS_SEPARATOR{
  130.             $prevToken $phpcsFile->findPrevious(T_WHITESPACE($prevToken - 1)nulltrue);
  131.             if ($tokens[$prevToken]['code'=== T_STRING{
  132.                 // Not in the global namespace.
  133.                 return;
  134.             }
  135.         }
  136.  
  137.         if (isset($ignore[$tokens[$prevToken]['code']]=== true{
  138.             // Not a call to a PHP function.
  139.             return;
  140.         }
  141.  
  142.         $nextToken $phpcsFile->findNext(T_WHITESPACE($stackPtr + 1)nulltrue);
  143.         if (isset($ignore[$tokens[$nextToken]['code']]=== true{
  144.             // Not a call to a PHP function.
  145.             return;
  146.         }
  147.  
  148.         if ($tokens[$stackPtr]['code'=== T_STRING && $tokens[$nextToken]['code'!== T_OPEN_PARENTHESIS{
  149.             // Not a call to a PHP function.
  150.             return;
  151.         }
  152.  
  153.         $function strtolower($tokens[$stackPtr]['content']);
  154.         $pattern  = null;
  155.  
  156.         if ($this->patternMatch === true{
  157.             $count   = 0;
  158.             $pattern preg_replace(
  159.                 $this->forbiddenFunctionNames,
  160.                 $this->forbiddenFunctionNames,
  161.                 $function,
  162.                 1,
  163.                 $count
  164.             );
  165.  
  166.             if ($count === 0{
  167.                 return;
  168.             }
  169.  
  170.             // Remove the pattern delimiters and modifier.
  171.             $pattern substr($pattern1-2);
  172.         else {
  173.             if (in_array($function$this->forbiddenFunctionNames=== false{
  174.                 return;
  175.             }
  176.         }//end if
  177.  
  178.         $this->addError($phpcsFile$stackPtr$function$pattern);
  179.  
  180.     }//end process()
  181.  
  182.  
  183.     /**
  184.      * Generates the error or warning for this sniff.
  185.      *
  186.      * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
  187.      * @param int                  $stackPtr  The position of the forbidden function
  188.      *                                         in the token array.
  189.      * @param string               $function  The name of the forbidden function.
  190.      * @param string               $pattern   The pattern used for the match.
  191.      *
  192.      * @return void 
  193.      */
  194.     protected function addError($phpcsFile$stackPtr$function$pattern=null)
  195.     {
  196.         $data  = array($function);
  197.         $error 'The use of function %s() is ';
  198.         if ($this->error === true{
  199.             $type   'Found';
  200.             $error .= 'forbidden';
  201.         else {
  202.             $type   'Discouraged';
  203.             $error .= 'discouraged';
  204.         }
  205.  
  206.         if ($pattern === null{
  207.             $pattern $function;
  208.         }
  209.  
  210.         if ($this->forbiddenFunctions[$pattern!== null
  211.             && $this->forbiddenFunctions[$pattern!== 'null'
  212.         {
  213.             $type  .= 'WithAlternative';
  214.             $data[$this->forbiddenFunctions[$pattern];
  215.             $error .= '; use %s() instead';
  216.         }
  217.  
  218.         if ($this->error === true{
  219.             $phpcsFile->addError($error$stackPtr$type$data);
  220.         else {
  221.             $phpcsFile->addWarning($error$stackPtr$type$data);
  222.         }
  223.  
  224.     }//end addError()
  225.  
  226.  
  227. }//end class

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