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

Source for file CreateWidgetTypeCallbackSniff.php

Documentation is available at CreateWidgetTypeCallbackSniff.php

  1. <?php
  2. /**
  3.  * Ensures the create() method of widget types properly uses callbacks.
  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\MySource\Sniffs\Objects;
  11.  
  12. use PHP_CodeSniffer\Sniffs\Sniff;
  13. use PHP_CodeSniffer\Files\File;
  14. use PHP_CodeSniffer\Util\Tokens;
  15.  
  16. class CreateWidgetTypeCallbackSniff implements Sniff
  17. {
  18.  
  19.     /**
  20.      * A list of tokenizers this sniff supports.
  21.      *
  22.      * @var array 
  23.      */
  24.     public $supportedTokenizers = array('JS');
  25.  
  26.  
  27.     /**
  28.      * Returns an array of tokens this test wants to listen for.
  29.      *
  30.      * @return array 
  31.      */
  32.     public function register()
  33.     {
  34.         return array(T_OBJECT);
  35.  
  36.     }//end register()
  37.  
  38.  
  39.     /**
  40.      * Processes this test, when one of its tokens is encountered.
  41.      *
  42.      * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
  43.      * @param int                         $stackPtr  The position of the current token
  44.      *                                                in the stack passed in $tokens.
  45.      *
  46.      * @return void 
  47.      */
  48.     public function process(File $phpcsFile$stackPtr)
  49.     {
  50.         $tokens $phpcsFile->getTokens();
  51.  
  52.         $className $phpcsFile->findPrevious(T_STRING($stackPtr - 1));
  53.         if (substr(strtolower($tokens[$className]['content'])-10!== 'widgettype'{
  54.             return;
  55.         }
  56.  
  57.         // Search for a create method.
  58.         $create $phpcsFile->findNext(T_PROPERTY$stackPtr$tokens[$stackPtr]['bracket_closer']null'create');
  59.         if ($create === false{
  60.             return;
  61.         }
  62.  
  63.         $function $phpcsFile->findNext(array(T_WHITESPACET_COLON)($create + 1)nulltrue);
  64.         if ($tokens[$function]['code'!== T_FUNCTION
  65.             && $tokens[$function]['code'!== T_CLOSURE
  66.         {
  67.             return;
  68.         }
  69.  
  70.         $start ($tokens[$function]['scope_opener'+ 1);
  71.         $end   ($tokens[$function]['scope_closer'- 1);
  72.  
  73.         // Check that the first argument is called "callback".
  74.         $arg $phpcsFile->findNext(T_WHITESPACE($tokens[$function]['parenthesis_opener'+ 1)nulltrue);
  75.         if ($tokens[$arg]['content'!== 'callback'{
  76.             $error 'The first argument of the create() method of a widget type must be called "callback"';
  77.             $phpcsFile->addError($error$arg'FirstArgNotCallback');
  78.         }
  79.  
  80.         /*
  81.             Look for return statements within the function. They cannot return
  82.             anything and must be preceded by the callback.call() line. The
  83.             callback itself must contain "self" or "this" as the first argument
  84.             and there needs to be a call to the callback function somewhere
  85.             in the create method. All calls to the callback function must be
  86.             followed by a return statement or the end of the method.
  87.         */
  88.  
  89.         $foundCallback  = false;
  90.         $passedCallback = false;
  91.         $nestedFunction = null;
  92.         for ($i $start$i <= $end$i++{
  93.             // Keep track of nested functions.
  94.             if ($nestedFunction !== null{
  95.                 if ($i === $nestedFunction{
  96.                     $nestedFunction = null;
  97.                     continue;
  98.                 }
  99.             else if (($tokens[$i]['code'=== T_FUNCTION
  100.                 || $tokens[$i]['code'=== T_CLOSURE)
  101.                 && isset($tokens[$i]['scope_closer']=== true
  102.             {
  103.                 $nestedFunction $tokens[$i]['scope_closer'];
  104.                 continue;
  105.             }
  106.  
  107.             if ($nestedFunction === null && $tokens[$i]['code'=== T_RETURN{
  108.                 // Make sure return statements are not returning anything.
  109.                 if ($tokens[($i + 1)]['code'!== T_SEMICOLON{
  110.                     $error 'The create() method of a widget type must not return a value';
  111.                     $phpcsFile->addError($error$i'ReturnValue');
  112.                 }
  113.  
  114.                 continue;
  115.             else if ($tokens[$i]['code'!== T_STRING
  116.                 || $tokens[$i]['content'!== 'callback'
  117.             {
  118.                 continue;
  119.             }
  120.  
  121.             // If this is the form "callback.call(" then it is a call
  122.             // to the callback function.
  123.             if ($tokens[($i + 1)]['code'!== T_OBJECT_OPERATOR
  124.                 || $tokens[($i + 2)]['content'!== 'call'
  125.                 || $tokens[($i + 3)]['code'!== T_OPEN_PARENTHESIS
  126.             {
  127.                 // One last chance; this might be the callback function
  128.                 // being passed to another function, like this
  129.                 // "this.init(something, callback, something)".
  130.                 if (isset($tokens[$i]['nested_parenthesis']=== false{
  131.                     continue;
  132.                 }
  133.  
  134.                 // Just make sure those brackets dont belong to anyone,
  135.                 // like an IF or FOR statement.
  136.                 foreach ($tokens[$i]['nested_parenthesis'as $bracket{
  137.                     if (isset($tokens[$bracket]['parenthesis_owner']=== true{
  138.                         continue(2);
  139.                     }
  140.                 }
  141.  
  142.                 // Note that we use this endBracket down further when checking
  143.                 // for a RETURN statement.
  144.                 $endBracket end($tokens[$i]['nested_parenthesis']);
  145.                 $bracket    key($tokens[$i]['nested_parenthesis']);
  146.  
  147.                 $prev $phpcsFile->findPrevious(
  148.                     Tokens::$emptyTokens,
  149.                     ($bracket - 1),
  150.                     null,
  151.                     true
  152.                 );
  153.  
  154.                 if ($tokens[$prev]['code'!== T_STRING{
  155.                     // This is not a function passing the callback.
  156.                     continue;
  157.                 }
  158.  
  159.                 $passedCallback = true;
  160.             }//end if
  161.  
  162.             $foundCallback = true;
  163.  
  164.             if ($passedCallback === false{
  165.                 // The first argument must be "this" or "self".
  166.                 $arg $phpcsFile->findNext(T_WHITESPACE($i + 4)nulltrue);
  167.                 if ($tokens[$arg]['content'!== 'this'
  168.                     && $tokens[$arg]['content'!== 'self'
  169.                 {
  170.                     $error 'The first argument passed to the callback function must be "this" or "self"';
  171.                     $phpcsFile->addError($error$arg'FirstArgNotSelf');
  172.                 }
  173.             }
  174.  
  175.             // Now it must be followed by a return statement or the end of the function.
  176.             if ($passedCallback === false{
  177.                 $endBracket $tokens[($i + 3)]['parenthesis_closer'];
  178.             }
  179.  
  180.             for ($next $endBracket$next <= $end$next++{
  181.                 // Skip whitespace so we find the next content after the call.
  182.                 if (isset(Tokens::$emptyTokens[$tokens[$next]['code']]=== true{
  183.                     continue;
  184.                 }
  185.  
  186.                 // Skip closing braces like END IF because it is not executable code.
  187.                 if ($tokens[$next]['code'=== T_CLOSE_CURLY_BRACKET{
  188.                     continue;
  189.                 }
  190.  
  191.                 // We don't care about anything on the current line, like a
  192.                 // semicolon. It doesn't matter if there are other statements on the
  193.                 // line because another sniff will check for those.
  194.                 if ($tokens[$next]['line'=== $tokens[$endBracket]['line']{
  195.                     continue;
  196.                 }
  197.  
  198.                 break;
  199.             }
  200.  
  201.             if ($next !== $tokens[$function]['scope_closer']
  202.                 && $tokens[$next]['code'!== T_RETURN
  203.             {
  204.                 $error 'The call to the callback function must be followed by a return statement if it is not the last statement in the create() method';
  205.                 $phpcsFile->addError($error$i'NoReturn');
  206.             }
  207.         }//end for
  208.  
  209.         if ($foundCallback === false{
  210.             $error 'The create() method of a widget type must call the callback function';
  211.             $phpcsFile->addError($error$create'CallbackNotCalled');
  212.         }
  213.  
  214.     }//end process()
  215.  
  216.  
  217. }//end class

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