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

Source for file FunctionCallSignatureSniff.php

Documentation is available at FunctionCallSignatureSniff.php

  1. <?php
  2. /**
  3.  * Ensures function calls are formatted correctly.
  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\Functions;
  11.  
  12. use PHP_CodeSniffer\Sniffs\Sniff;
  13. use PHP_CodeSniffer\Files\File;
  14. use PHP_CodeSniffer\Util\Tokens;
  15.  
  16. class FunctionCallSignatureSniff implements Sniff
  17. {
  18.  
  19.     /**
  20.      * A list of tokenizers this sniff supports.
  21.      *
  22.      * @var array 
  23.      */
  24.     public $supportedTokenizers = array(
  25.                                    'PHP',
  26.                                    'JS',
  27.                                   );
  28.  
  29.     /**
  30.      * The number of spaces code should be indented.
  31.      *
  32.      * @var integer 
  33.      */
  34.     public $indent = 4;
  35.  
  36.     /**
  37.      * If TRUE, multiple arguments can be defined per line in a multi-line call.
  38.      *
  39.      * @var boolean 
  40.      */
  41.     public $allowMultipleArguments = true;
  42.  
  43.     /**
  44.      * How many spaces should follow the opening bracket.
  45.      *
  46.      * @var integer 
  47.      */
  48.     public $requiredSpacesAfterOpen = 0;
  49.  
  50.     /**
  51.      * How many spaces should precede the closing bracket.
  52.      *
  53.      * @var integer 
  54.      */
  55.     public $requiredSpacesBeforeClose = 0;
  56.  
  57.  
  58.     /**
  59.      * Returns an array of tokens this test wants to listen for.
  60.      *
  61.      * @return array 
  62.      */
  63.     public function register()
  64.     {
  65.         $tokens = Tokens::$functionNameTokens;
  66.  
  67.         $tokens[= T_VARIABLE;
  68.         $tokens[T_CLOSE_CURLY_BRACKET;
  69.         $tokens[T_CLOSE_PARENTHESIS;
  70.  
  71.         return $tokens;
  72.  
  73.     }//end register()
  74.  
  75.  
  76.     /**
  77.      * Processes this test, when one of its tokens is encountered.
  78.      *
  79.      * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
  80.      * @param int                         $stackPtr  The position of the current token
  81.      *                                                in the stack passed in $tokens.
  82.      *
  83.      * @return void 
  84.      */
  85.     public function process(File $phpcsFile$stackPtr)
  86.     {
  87.         $this->requiredSpacesAfterOpen   = (int) $this->requiredSpacesAfterOpen;
  88.         $this->requiredSpacesBeforeClose = (int) $this->requiredSpacesBeforeClose;
  89.         $tokens $phpcsFile->getTokens();
  90.  
  91.         if ($tokens[$stackPtr]['code'=== T_CLOSE_CURLY_BRACKET
  92.             && isset($tokens[$stackPtr]['scope_condition']=== true
  93.         {
  94.             // Not a function call.
  95.             return;
  96.         }
  97.  
  98.         // Find the next non-empty token.
  99.         $openBracket $phpcsFile->findNext(Tokens::$emptyTokens($stackPtr + 1)nulltrue);
  100.  
  101.         if ($tokens[$openBracket]['code'!== T_OPEN_PARENTHESIS{
  102.             // Not a function call.
  103.             return;
  104.         }
  105.  
  106.         if (isset($tokens[$openBracket]['parenthesis_closer']=== false{
  107.             // Not a function call.
  108.             return;
  109.         }
  110.  
  111.         // Find the previous non-empty token.
  112.         $search   = Tokens::$emptyTokens;
  113.         $search[= T_BITWISE_AND;
  114.         $previous $phpcsFile->findPrevious($search($stackPtr - 1)nulltrue);
  115.         if ($tokens[$previous]['code'=== T_FUNCTION{
  116.             // It's a function definition, not a function call.
  117.             return;
  118.         }
  119.  
  120.         $closeBracket $tokens[$openBracket]['parenthesis_closer'];
  121.  
  122.         if (($stackPtr + 1!== $openBracket{
  123.             // Checking this: $value = my_function[*](...).
  124.             $error 'Space before opening parenthesis of function call prohibited';
  125.             $fix   $phpcsFile->addFixableError($error$stackPtr'SpaceBeforeOpenBracket');
  126.             if ($fix === true{
  127.                 $phpcsFile->fixer->beginChangeset();
  128.                 for ($i ($stackPtr + 1)$i $openBracket$i++{
  129.                     $phpcsFile->fixer->replaceToken($i'');
  130.                 }
  131.  
  132.                 // Modify the bracket as well to ensure a conflict if the bracket
  133.                 // has been changed in some way by another sniff.
  134.                 $phpcsFile->fixer->replaceToken($openBracket'(');
  135.                 $phpcsFile->fixer->endChangeset();
  136.             }
  137.         }
  138.  
  139.         $next $phpcsFile->findNext(T_WHITESPACE($closeBracket + 1)nulltrue);
  140.         if ($tokens[$next]['code'=== T_SEMICOLON{
  141.             if (isset(Tokens::$emptyTokens[$tokens[($closeBracket + 1)]['code']]=== true{
  142.                 $error 'Space after closing parenthesis of function call prohibited';
  143.                 $fix   $phpcsFile->addFixableError($error$closeBracket'SpaceAfterCloseBracket');
  144.                 if ($fix === true{
  145.                     $phpcsFile->fixer->beginChangeset();
  146.                     for ($i ($closeBracket + 1)$i $next$i++{
  147.                         $phpcsFile->fixer->replaceToken($i'');
  148.                     }
  149.  
  150.                     // Modify the bracket as well to ensure a conflict if the bracket
  151.                     // has been changed in some way by another sniff.
  152.                     $phpcsFile->fixer->replaceToken($closeBracket')');
  153.                     $phpcsFile->fixer->endChangeset();
  154.                 }
  155.             }
  156.         }
  157.  
  158.         // Check if this is a single line or multi-line function call.
  159.         if ($this->isMultiLineCall($phpcsFile$stackPtr$openBracket$tokens=== true{
  160.             $this->processMultiLineCall($phpcsFile$stackPtr$openBracket$tokens);
  161.         else {
  162.             $this->processSingleLineCall($phpcsFile$stackPtr$openBracket$tokens);
  163.         }
  164.  
  165.     }//end process()
  166.  
  167.  
  168.     /**
  169.      * Determine if this is a multi-line function call.
  170.      *
  171.      * @param \PHP_CodeSniffer\Files\File $phpcsFile   The file being scanned.
  172.      * @param int                         $stackPtr    The position of the current token
  173.      *                                                  in the stack passed in $tokens.
  174.      * @param int                         $openBracket The position of the opening bracket
  175.      *                                                  in the stack passed in $tokens.
  176.      * @param array                       $tokens      The stack of tokens that make up
  177.      *                                                  the file.
  178.      *
  179.      * @return void 
  180.      */
  181.     public function isMultiLineCall(File $phpcsFile$stackPtr$openBracket$tokens)
  182.     {
  183.         $closeBracket $tokens[$openBracket]['parenthesis_closer'];
  184.         if ($tokens[$openBracket]['line'!== $tokens[$closeBracket]['line']{
  185.             return true;
  186.         }
  187.  
  188.         return false;
  189.  
  190.     }//end isMultiLineCall()
  191.  
  192.  
  193.     /**
  194.      * Processes single-line calls.
  195.      *
  196.      * @param \PHP_CodeSniffer\Files\File $phpcsFile   The file being scanned.
  197.      * @param int                         $stackPtr    The position of the current token
  198.      *                                                  in the stack passed in $tokens.
  199.      * @param int                         $openBracket The position of the opening bracket
  200.      *                                                  in the stack passed in $tokens.
  201.      * @param array                       $tokens      The stack of tokens that make up
  202.      *                                                  the file.
  203.      *
  204.      * @return void 
  205.      */
  206.     public function processSingleLineCall(File $phpcsFile$stackPtr$openBracket$tokens)
  207.     {
  208.         // If the function call has no arguments or comments, enforce 0 spaces.
  209.         $closer $tokens[$openBracket]['parenthesis_closer'];
  210.         if ($openBracket === ($closer - 1)) {
  211.             return;
  212.         }
  213.  
  214.         $next $phpcsFile->findNext(T_WHITESPACE($openBracket + 1)$closertrue);
  215.         if ($next === false{
  216.             $requiredSpacesAfterOpen   = 0;
  217.             $requiredSpacesBeforeClose = 0;
  218.         else {
  219.             $requiredSpacesAfterOpen   $this->requiredSpacesAfterOpen;
  220.             $requiredSpacesBeforeClose $this->requiredSpacesBeforeClose;
  221.         }
  222.  
  223.         if ($requiredSpacesAfterOpen === 0 && $tokens[($openBracket + 1)]['code'=== T_WHITESPACE{
  224.             // Checking this: $value = my_function([*]...).
  225.             $error 'Space after opening parenthesis of function call prohibited';
  226.             $fix   $phpcsFile->addFixableError($error$stackPtr'SpaceAfterOpenBracket');
  227.             if ($fix === true{
  228.                 $phpcsFile->fixer->replaceToken(($openBracket + 1)'');
  229.             }
  230.         else if ($requiredSpacesAfterOpen > 0{
  231.             $spaceAfterOpen = 0;
  232.             if ($tokens[($openBracket + 1)]['code'=== T_WHITESPACE{
  233.                 $spaceAfterOpen strlen($tokens[($openBracket + 1)]['content']);
  234.             }
  235.  
  236.             if ($spaceAfterOpen !== $requiredSpacesAfterOpen{
  237.                 $error 'Expected %s spaces after opening bracket; %s found';
  238.                 $data  = array(
  239.                           $requiredSpacesAfterOpen,
  240.                           $spaceAfterOpen,
  241.                          );
  242.                 $fix   $phpcsFile->addFixableError($error$stackPtr'SpaceAfterOpenBracket'$data);
  243.                 if ($fix === true{
  244.                     $padding str_repeat(' '$requiredSpacesAfterOpen);
  245.                     if ($spaceAfterOpen === 0{
  246.                         $phpcsFile->fixer->addContent($openBracket$padding);
  247.                     else {
  248.                         $phpcsFile->fixer->replaceToken(($openBracket + 1)$padding);
  249.                     }
  250.                 }
  251.             }
  252.         }//end if
  253.  
  254.         // Checking this: $value = my_function(...[*]).
  255.         $spaceBeforeClose = 0;
  256.         $prev $phpcsFile->findPrevious(T_WHITESPACE($closer - 1)$openBrackettrue);
  257.         if ($tokens[$prev]['code'=== T_END_HEREDOC || $tokens[$prev]['code'=== T_END_NOWDOC{
  258.             // Need a newline after these tokens, so ignore this rule.
  259.             return;
  260.         }
  261.  
  262.         if ($tokens[$prev]['line'!== $tokens[$closer]['line']{
  263.             $spaceBeforeClose 'newline';
  264.         else if ($tokens[($closer - 1)]['code'=== T_WHITESPACE{
  265.             $spaceBeforeClose strlen($tokens[($closer - 1)]['content']);
  266.         }
  267.  
  268.         if ($spaceBeforeClose !== $requiredSpacesBeforeClose{
  269.             $error 'Expected %s spaces before closing bracket; %s found';
  270.             $data  = array(
  271.                       $requiredSpacesBeforeClose,
  272.                       $spaceBeforeClose,
  273.                      );
  274.             $fix   $phpcsFile->addFixableError($error$stackPtr'SpaceBeforeCloseBracket'$data);
  275.             if ($fix === true{
  276.                 $padding str_repeat(' '$requiredSpacesBeforeClose);
  277.  
  278.                 if ($spaceBeforeClose === 0{
  279.                     $phpcsFile->fixer->addContentBefore($closer$padding);
  280.                 else if ($spaceBeforeClose === 'newline'{
  281.                     $phpcsFile->fixer->beginChangeset();
  282.  
  283.                     $closingContent ')';
  284.  
  285.                     $next $phpcsFile->findNext(T_WHITESPACE($closer + 1)nulltrue);
  286.                     if ($tokens[$next]['code'=== T_SEMICOLON{
  287.                         $closingContent .= ';';
  288.                         for ($i ($closer + 1)$i <= $next$i++{
  289.                             $phpcsFile->fixer->replaceToken($i'');
  290.                         }
  291.                     }
  292.  
  293.                     // We want to jump over any whitespace or inline comment and
  294.                     // move the closing parenthesis after any other token.
  295.                     $prev ($closer - 1);
  296.                     while (isset(Tokens::$emptyTokens[$tokens[$prev]['code']]=== true{
  297.                         if (($tokens[$prev]['code'=== T_COMMENT)
  298.                             && (strpos($tokens[$prev]['content']'*/'!== false)
  299.                         {
  300.                             break;
  301.                         }
  302.  
  303.                         $prev--;
  304.                     }
  305.  
  306.                     $phpcsFile->fixer->addContent($prev$padding.$closingContent);
  307.  
  308.                     $prevNonWhitespace $phpcsFile->findPrevious(T_WHITESPACE($closer - 1)nulltrue);
  309.                     for ($i ($prevNonWhitespace + 1)$i <= $closer$i++{
  310.                         $phpcsFile->fixer->replaceToken($i'');
  311.                     }
  312.  
  313.                     $phpcsFile->fixer->endChangeset();
  314.                 else {
  315.                     $phpcsFile->fixer->replaceToken(($closer - 1)$padding);
  316.                 }//end if
  317.             }//end if
  318.         }//end if
  319.  
  320.     }//end processSingleLineCall()
  321.  
  322.  
  323.     /**
  324.      * Processes multi-line calls.
  325.      *
  326.      * @param \PHP_CodeSniffer\Files\File $phpcsFile   The file being scanned.
  327.      * @param int                         $stackPtr    The position of the current token
  328.      *                                                  in the stack passed in $tokens.
  329.      * @param int                         $openBracket The position of the opening bracket
  330.      *                                                  in the stack passed in $tokens.
  331.      * @param array                       $tokens      The stack of tokens that make up
  332.      *                                                  the file.
  333.      *
  334.      * @return void 
  335.      */
  336.     public function processMultiLineCall(File $phpcsFile$stackPtr$openBracket$tokens)
  337.     {
  338.         // We need to work out how far indented the function
  339.         // call itself is, so we can work out how far to
  340.         // indent the arguments.
  341.         $start $phpcsFile->findStartOfStatement($stackPtr);
  342.         foreach (array('stackPtr''start'as $checkToken{
  343.             $x = $$checkToken;
  344.             for ($i ($x - 1)$i >= 0; $i--{
  345.                 if ($tokens[$i]['line'!== $tokens[$x]['line']{
  346.                     $i++;
  347.                     break;
  348.                 }
  349.             }
  350.  
  351.             if ($i <= 0{
  352.                 $functionIndent = 0;
  353.             else if ($tokens[$i]['code'=== T_WHITESPACE{
  354.                 $functionIndent strlen($tokens[$i]['content']);
  355.             else if ($tokens[$i]['code'=== T_CONSTANT_ENCAPSED_STRING{
  356.                 $functionIndent = 0;
  357.             else {
  358.                 $trimmed ltrim($tokens[$i]['content']);
  359.                 if ($trimmed === ''{
  360.                     if ($tokens[$i]['code'=== T_INLINE_HTML{
  361.                         $functionIndent strlen($tokens[$i]['content']);
  362.                     else {
  363.                         $functionIndent ($tokens[$i]['column'- 1);
  364.                     }
  365.                 else {
  366.                     $functionIndent (strlen($tokens[$i]['content']strlen($trimmed));
  367.                 }
  368.             }
  369.  
  370.             $varName  $checkToken.'Indent';
  371.             $$varName $functionIndent;
  372.         }//end foreach
  373.  
  374.         $functionIndent max($startIndent$stackPtrIndent);
  375.  
  376.         $next $phpcsFile->findNext(Tokens::$emptyTokens($openBracket + 1)nulltrue);
  377.         if ($tokens[$next]['line'=== $tokens[$openBracket]['line']{
  378.             $error 'Opening parenthesis of a multi-line function call must be the last content on the line';
  379.             $fix   $phpcsFile->addFixableError($error$stackPtr'ContentAfterOpenBracket');
  380.             if ($fix === true{
  381.                 $phpcsFile->fixer->addContent(
  382.                     $openBracket,
  383.                     $phpcsFile->eolChar.str_repeat(' '($functionIndent $this->indent))
  384.                 );
  385.             }
  386.         }
  387.  
  388.         $closeBracket $tokens[$openBracket]['parenthesis_closer'];
  389.         $prev         $phpcsFile->findPrevious(T_WHITESPACE($closeBracket - 1)nulltrue);
  390.         if ($tokens[$prev]['line'=== $tokens[$closeBracket]['line']{
  391.             $error 'Closing parenthesis of a multi-line function call must be on a line by itself';
  392.             $fix   $phpcsFile->addFixableError($error$closeBracket'CloseBracketLine');
  393.             if ($fix === true{
  394.                 $phpcsFile->fixer->addContentBefore(
  395.                     $closeBracket,
  396.                     $phpcsFile->eolChar.str_repeat(' '($functionIndent $this->indent))
  397.                 );
  398.             }
  399.         }
  400.  
  401.         // Each line between the parenthesis should be indented n spaces.
  402.         $lastLine ($tokens[$openBracket]['line'- 1);
  403.         $argStart = null;
  404.         $argEnd   = null;
  405.         $inArg    = false;
  406.  
  407.         // Start processing at the first argument.
  408.         $i $phpcsFile->findNext(T_WHITESPACE($openBracket + 1)nulltrue);
  409.         if ($tokens[($i - 1)]['code'=== T_WHITESPACE
  410.             && $tokens[($i - 1)]['line'=== $tokens[$i]['line']
  411.         {
  412.             // Make sure we check the indent.
  413.             $i--;
  414.         }
  415.  
  416.         for ($i$i $closeBracket$i++{
  417.             if ($i $argStart && $i $argEnd{
  418.                 $inArg = true;
  419.             else {
  420.                 $inArg = false;
  421.             }
  422.  
  423.             if ($tokens[$i]['line'!== $lastLine{
  424.                 $lastLine $tokens[$i]['line'];
  425.  
  426.                 // Ignore heredoc indentation.
  427.                 if (isset(Tokens::$heredocTokens[$tokens[$i]['code']]=== true{
  428.                     continue;
  429.                 }
  430.  
  431.                 // Ignore multi-line string indentation.
  432.                 if (isset(Tokens::$stringTokens[$tokens[$i]['code']]=== true
  433.                     && $tokens[$i]['code'=== $tokens[($i - 1)]['code']
  434.                 {
  435.                     continue;
  436.                 }
  437.  
  438.                 // Ignore inline HTML.
  439.                 if ($tokens[$i]['code'=== T_INLINE_HTML{
  440.                     continue;
  441.                 }
  442.  
  443.                 if ($tokens[$i]['line'!== $tokens[$openBracket]['line']{
  444.                     // We changed lines, so this should be a whitespace indent token, but first make
  445.                     // sure it isn't a blank line because we don't need to check indent unless there
  446.                     // is actually some code to indent.
  447.                     if ($tokens[$i]['code'=== T_WHITESPACE{
  448.                         $nextCode $phpcsFile->findNext(T_WHITESPACE($i + 1)($closeBracket + 1)true);
  449.                         if ($tokens[$nextCode]['line'!== $lastLine{
  450.                             if ($inArg === false{
  451.                                 $error 'Empty lines are not allowed in multi-line function calls';
  452.                                 $fix   $phpcsFile->addFixableError($error$i'EmptyLine');
  453.                                 if ($fix === true{
  454.                                     $phpcsFile->fixer->replaceToken($i'');
  455.                                 }
  456.                             }
  457.  
  458.                             continue;
  459.                         }
  460.                     else {
  461.                         $nextCode $i;
  462.                     }
  463.  
  464.                     if ($tokens[$nextCode]['line'=== $tokens[$closeBracket]['line']{
  465.                         // Closing brace needs to be indented to the same level
  466.                         // as the function call.
  467.                         $inArg          = false;
  468.                         $expectedIndent $functionIndent;
  469.                     else {
  470.                         $expectedIndent ($functionIndent $this->indent);
  471.                     }
  472.  
  473.                     if ($tokens[$i]['code'!== T_WHITESPACE
  474.                         && $tokens[$i]['code'!== T_DOC_COMMENT_WHITESPACE
  475.                     {
  476.                         // Just check if it is a multi-line block comment. If so, we can
  477.                         // calculate the indent from the whitespace before the content.
  478.                         if ($tokens[$i]['code'=== T_COMMENT
  479.                             && $tokens[($i - 1)]['code'=== T_COMMENT
  480.                         {
  481.                             $trimmedLength strlen(ltrim($tokens[$i]['content']));
  482.                             if ($trimmedLength === 0{
  483.                                 // This is a blank comment line, so indenting it is
  484.                                 // pointless.
  485.                                 continue;
  486.                             }
  487.  
  488.                             $foundIndent (strlen($tokens[$i]['content']$trimmedLength);
  489.                         else {
  490.                             $foundIndent = 0;
  491.                         }
  492.                     else {
  493.                         $foundIndent strlen($tokens[$i]['content']);
  494.                     }
  495.  
  496.                     if ($foundIndent $expectedIndent
  497.                         || ($inArg === false
  498.                         && $expectedIndent !== $foundIndent)
  499.                     {
  500.                         $error 'Multi-line function call not indented correctly; expected %s spaces but found %s';
  501.                         $data  = array(
  502.                                   $expectedIndent,
  503.                                   $foundIndent,
  504.                                  );
  505.  
  506.                         $fix $phpcsFile->addFixableError($error$i'Indent'$data);
  507.                         if ($fix === true{
  508.                             $padding str_repeat(' '$expectedIndent);
  509.                             if ($foundIndent === 0{
  510.                                 $phpcsFile->fixer->addContentBefore($i$padding);
  511.                             else {
  512.                                 if ($tokens[$i]['code'=== T_COMMENT{
  513.                                     $comment $padding.ltrim($tokens[$i]['content']);
  514.                                     $phpcsFile->fixer->replaceToken($i$comment);
  515.                                 else {
  516.                                     $phpcsFile->fixer->replaceToken($i$padding);
  517.                                 }
  518.                             }
  519.                         }
  520.                     }//end if
  521.                 else {
  522.                     $nextCode $i;
  523.                 }//end if
  524.  
  525.                 if ($inArg === false{
  526.                     $argStart $nextCode;
  527.                     $argEnd   $phpcsFile->findEndOfStatement($nextCode);
  528.                 }
  529.             }//end if
  530.  
  531.             // If we are within an argument we should be ignoring commas
  532.             // as these are not signaling the end of an argument.
  533.             if ($inArg === false && $tokens[$i]['code'=== T_COMMA{
  534.                 $next $phpcsFile->findNext(array(T_WHITESPACET_COMMENT)($i + 1)$closeBrackettrue);
  535.                 if ($next === false{
  536.                     continue;
  537.                 }
  538.  
  539.                 if ($this->allowMultipleArguments === false{
  540.                     // Comma has to be the last token on the line.
  541.                     if ($tokens[$i]['line'=== $tokens[$next]['line']{
  542.                         $error 'Only one argument is allowed per line in a multi-line function call';
  543.                         $fix   $phpcsFile->addFixableError($error$next'MultipleArguments');
  544.                         if ($fix === true{
  545.                             $phpcsFile->fixer->beginChangeset();
  546.                             for ($x ($next - 1)$x $i$x--{
  547.                                 if ($tokens[$x]['code'!== T_WHITESPACE{
  548.                                     break;
  549.                                 }
  550.  
  551.                                 $phpcsFile->fixer->replaceToken($x'');
  552.                             }
  553.  
  554.                             $phpcsFile->fixer->addContentBefore(
  555.                                 $next,
  556.                                 $phpcsFile->eolChar.str_repeat(' '($functionIndent $this->indent))
  557.                             );
  558.                             $phpcsFile->fixer->endChangeset();
  559.                         }
  560.                     }
  561.                 }//end if
  562.  
  563.                 $argStart $next;
  564.                 $argEnd   $phpcsFile->findEndOfStatement($next);
  565.             }//end if
  566.         }//end for
  567.  
  568.     }//end processMultiLineCall()
  569.  
  570.  
  571. }//end class

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