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

Source for file Fixer.php

Documentation is available at Fixer.php

  1. <?php
  2. /**
  3.  * A helper class for fixing errors.
  4.  *
  5.  * Provides helper functions that act upon a token array and modify the file
  6.  * content.
  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;
  14.  
  15. use PHP_CodeSniffer\Files\File;
  16. use PHP_CodeSniffer\Util\Common;
  17.  
  18. class Fixer
  19. {
  20.  
  21.     /**
  22.      * Is the fixer enabled and fixing a file?
  23.      *
  24.      * Sniffs should check this value to ensure they are not
  25.      * doing extra processing to prepare for a fix when fixing is
  26.      * not required.
  27.      *
  28.      * @var boolean 
  29.      */
  30.     public $enabled = false;
  31.  
  32.     /**
  33.      * The number of times we have looped over a file.
  34.      *
  35.      * @var integer 
  36.      */
  37.     public $loops = 0;
  38.  
  39.     /**
  40.      * The file being fixed.
  41.      *
  42.      * @var \PHP_CodeSniffer\Files\File 
  43.      */
  44.     private $currentFile = null;
  45.  
  46.     /**
  47.      * The list of tokens that make up the file contents.
  48.      *
  49.      * This is a simplified list which just contains the token content and nothing
  50.      * else. This is the array that is updated as fixes are made, not the file's
  51.      * token array. Imploding this array will give you the file content back.
  52.      *
  53.      * @var array<int, string>
  54.      */
  55.     private $tokens = array();
  56.  
  57.     /**
  58.      * A list of tokens that have already been fixed.
  59.      *
  60.      * We don't allow the same token to be fixed more than once each time
  61.      * through a file as this can easily cause conflicts between sniffs.
  62.      *
  63.      * @var int[] 
  64.      */
  65.     private $fixedTokens = array();
  66.  
  67.     /**
  68.      * The last value of each fixed token.
  69.      *
  70.      * If a token is being "fixed" back to its last value, the fix is
  71.      * probably conflicting with another.
  72.      *
  73.      * @var array<int, string>
  74.      */
  75.     private $oldTokenValues = array();
  76.  
  77.     /**
  78.      * A list of tokens that have been fixed during a changeset.
  79.      *
  80.      * All changes in changeset must be able to be applied, or else
  81.      * the entire changeset is rejected.
  82.      *
  83.      * @var array 
  84.      */
  85.     private $changeset = array();
  86.  
  87.     /**
  88.      * Is there an open changeset.
  89.      *
  90.      * @var boolean 
  91.      */
  92.     private $inChangeset = false;
  93.  
  94.     /**
  95.      * Is the current fixing loop in conflict?
  96.      *
  97.      * @var boolean 
  98.      */
  99.     private $inConflict = false;
  100.  
  101.     /**
  102.      * The number of fixes that have been performed.
  103.      *
  104.      * @var integer 
  105.      */
  106.     private $numFixes = 0;
  107.  
  108.  
  109.     /**
  110.      * Starts fixing a new file.
  111.      *
  112.      * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being fixed.
  113.      *
  114.      * @return void 
  115.      */
  116.     public function startFile(File $phpcsFile)
  117.     {
  118.         $this->currentFile $phpcsFile;
  119.         $this->numFixes    = 0;
  120.         $this->fixedTokens = array();
  121.  
  122.         $tokens       $phpcsFile->getTokens();
  123.         $this->tokens = array();
  124.         foreach ($tokens as $index => $token{
  125.             if (isset($token['orig_content']=== true{
  126.                 $this->tokens[$index$token['orig_content'];
  127.             else {
  128.                 $this->tokens[$index$token['content'];
  129.             }
  130.         }
  131.  
  132.     }//end startFile()
  133.  
  134.  
  135.     /**
  136.      * Attempt to fix the file by processing it until no fixes are made.
  137.      *
  138.      * @return boolean 
  139.      */
  140.     public function fixFile()
  141.     {
  142.         $fixable $this->currentFile->getFixableCount();
  143.         if ($fixable === 0{
  144.             // Nothing to fix.
  145.             return false;
  146.         }
  147.  
  148.         $stdin = false;
  149.         if (empty($this->currentFile->config->files=== true{
  150.             $stdin = true;
  151.         }
  152.  
  153.         $this->enabled = true;
  154.  
  155.         $this->loops = 0;
  156.         while ($this->loops < 50{
  157.             ob_start();
  158.  
  159.             // Only needed once file content has changed.
  160.             $contents $this->getContents();
  161.  
  162.             if (PHP_CODESNIFFER_VERBOSITY > 2{
  163.                 @ob_end_clean();
  164.                 echo '---START FILE CONTENT---'.PHP_EOL;
  165.                 $lines explode($this->currentFile->eolChar$contents);
  166.                 $max   strlen(count($lines));
  167.                 foreach ($lines as $lineNum => $line{
  168.                     $lineNum++;
  169.                     echo str_pad($lineNum$max' 'STR_PAD_LEFT).'|'.$line.PHP_EOL;
  170.                 }
  171.  
  172.                 echo '--- END FILE CONTENT ---'.PHP_EOL;
  173.                 ob_start();
  174.             }
  175.  
  176.             $this->inConflict = false;
  177.             $this->currentFile->ruleset->populateTokenListeners();
  178.             $this->currentFile->setContent($contents);
  179.             $this->currentFile->process();
  180.             ob_end_clean();
  181.  
  182.             $this->loops++;
  183.  
  184.             if (PHP_CODESNIFFER_CBF === true && PHP_CODESNIFFER_VERBOSITY > 0{
  185.                 echo "\r".str_repeat(' '80)."\r";
  186.                 echo "\t=> Fixing file: $this->numFixes/$fixable violations remaining [made $this->loops pass";
  187.                 if ($this->loops > 1{
  188.                     echo 'es';
  189.                 }
  190.  
  191.                 echo ']... ';
  192.             }
  193.  
  194.             if ($this->numFixes === 0 && $this->inConflict === false{
  195.                 // Nothing left to do.
  196.                 break;
  197.             else if (PHP_CODESNIFFER_VERBOSITY > 1{
  198.                 echo "\t* fixed $this->numFixes violations, starting loop ".($this->loops + 1).' *'.PHP_EOL;
  199.             }
  200.         }//end while
  201.  
  202.         $this->enabled = false;
  203.  
  204.         if ($this->numFixes > 0{
  205.             if (PHP_CODESNIFFER_VERBOSITY > 1{
  206.                 if (ob_get_level(> 0{
  207.                     ob_end_clean();
  208.                 }
  209.  
  210.                 echo "\t*** Reached maximum number of loops with $this->numFixes violations left unfixed ***".PHP_EOL;
  211.                 ob_start();
  212.             }
  213.  
  214.             return false;
  215.         }
  216.  
  217.         return true;
  218.  
  219.     }//end fixFile()
  220.  
  221.  
  222.     /**
  223.      * Generates a text diff of the original file and the new content.
  224.      *
  225.      * @param string  $filePath Optional file path to diff the file against.
  226.      *                           If not specified, the original version of the
  227.      *                           file will be used.
  228.      * @param boolean $colors   Print colored output or not.
  229.      *
  230.      * @return string 
  231.      */
  232.     public function generateDiff($filePath=null$colors=true)
  233.     {
  234.         if ($filePath === null{
  235.             $filePath $this->currentFile->getFilename();
  236.         }
  237.  
  238.         $cwd getcwd().DIRECTORY_SEPARATOR;
  239.         if (strpos($filePath$cwd=== 0{
  240.             $filename substr($filePathstrlen($cwd));
  241.         else {
  242.             $filename $filePath;
  243.         }
  244.  
  245.         $contents $this->getContents();
  246.  
  247.         $tempName  tempnam(sys_get_temp_dir()'phpcs-fixer');
  248.         $fixedFile fopen($tempName'w');
  249.         fwrite($fixedFile$contents);
  250.  
  251.         // We must use something like shell_exec() because whitespace at the end
  252.         // of lines is critical to diff files.
  253.         $filename escapeshellarg($filename);
  254.         $cmd      = "diff -u -L$filename -LPHP_CodeSniffer $filename \"$tempName\"";
  255.  
  256.         $diff shell_exec($cmd);
  257.  
  258.         fclose($fixedFile);
  259.         if (is_file($tempName=== true{
  260.             unlink($tempName);
  261.         }
  262.  
  263.         if ($colors === false{
  264.             return $diff;
  265.         }
  266.  
  267.         $diffLines explode(PHP_EOL$diff);
  268.         if (count($diffLines=== 1{
  269.             // Seems to be required for cygwin.
  270.             $diffLines explode("\n"$diff);
  271.         }
  272.  
  273.         $diff = array();
  274.         foreach ($diffLines as $line{
  275.             if (isset($line[0]=== true{
  276.                 switch ($line[0]{
  277.                 case '-':
  278.                     $diff[= "\033[31m$line\033[0m";
  279.                     break;
  280.                 case '+':
  281.                     $diff[= "\033[32m$line\033[0m";
  282.                     break;
  283.                 default:
  284.                     $diff[$line;
  285.                 }
  286.             }
  287.         }
  288.  
  289.         $diff implode(PHP_EOL$diff);
  290.  
  291.         return $diff;
  292.  
  293.     }//end generateDiff()
  294.  
  295.  
  296.     /**
  297.      * Get a count of fixes that have been performed on the file.
  298.      *
  299.      * This value is reset every time a new file is started, or an existing
  300.      * file is restarted.
  301.      *
  302.      * @return int 
  303.      */
  304.     public function getFixCount()
  305.     {
  306.         return $this->numFixes;
  307.  
  308.     }//end getFixCount()
  309.  
  310.  
  311.     /**
  312.      * Get the current content of the file, as a string.
  313.      *
  314.      * @return string 
  315.      */
  316.     public function getContents()
  317.     {
  318.         $contents implode($this->tokens);
  319.         return $contents;
  320.  
  321.     }//end getContents()
  322.  
  323.  
  324.     /**
  325.      * Get the current fixed content of a token.
  326.      *
  327.      * This function takes changesets into account so should be used
  328.      * instead of directly accessing the token array.
  329.      *
  330.      * @param int $stackPtr The position of the token in the token stack.
  331.      *
  332.      * @return string 
  333.      */
  334.     public function getTokenContent($stackPtr)
  335.     {
  336.         if ($this->inChangeset === true
  337.             && isset($this->changeset[$stackPtr]=== true
  338.         {
  339.             return $this->changeset[$stackPtr];
  340.         else {
  341.             return $this->tokens[$stackPtr];
  342.         }
  343.  
  344.     }//end getTokenContent()
  345.  
  346.  
  347.     /**
  348.      * Start recording actions for a changeset.
  349.      *
  350.      * @return void 
  351.      */
  352.     public function beginChangeset()
  353.     {
  354.         if ($this->inConflict === true{
  355.             return false;
  356.         }
  357.  
  358.         if (PHP_CODESNIFFER_VERBOSITY > 1{
  359.             $bt    debug_backtrace();
  360.             $sniff $bt[1]['class'];
  361.             $line  $bt[0]['line'];
  362.  
  363.             @ob_end_clean();
  364.             echo "\t=> Changeset started by $sniff (line $line)".PHP_EOL;
  365.             ob_start();
  366.         }
  367.  
  368.         $this->changeset   = array();
  369.         $this->inChangeset = true;
  370.  
  371.     }//end beginChangeset()
  372.  
  373.  
  374.     /**
  375.      * Stop recording actions for a changeset, and apply logged changes.
  376.      *
  377.      * @return boolean 
  378.      */
  379.     public function endChangeset()
  380.     {
  381.         if ($this->inConflict === true{
  382.             return false;
  383.         }
  384.  
  385.         $this->inChangeset = false;
  386.  
  387.         $success = true;
  388.         $applied = array();
  389.         foreach ($this->changeset as $stackPtr => $content{
  390.             $success $this->replaceToken($stackPtr$content);
  391.             if ($success === false{
  392.                 break;
  393.             else {
  394.                 $applied[$stackPtr;
  395.             }
  396.         }
  397.  
  398.         if ($success === false{
  399.             // Rolling back all changes.
  400.             foreach ($applied as $stackPtr{
  401.                 $this->revertToken($stackPtr);
  402.             }
  403.  
  404.             if (PHP_CODESNIFFER_VERBOSITY > 1{
  405.                 @ob_end_clean();
  406.                 echo "\t=> Changeset failed to apply".PHP_EOL;
  407.                 ob_start();
  408.             }
  409.         else if (PHP_CODESNIFFER_VERBOSITY > 1{
  410.             $fixes count($this->changeset);
  411.             @ob_end_clean();
  412.             echo "\t=> Changeset ended: $fixes changes applied".PHP_EOL;
  413.             ob_start();
  414.         }
  415.  
  416.         $this->changeset = array();
  417.  
  418.     }//end endChangeset()
  419.  
  420.  
  421.     /**
  422.      * Stop recording actions for a changeset, and discard logged changes.
  423.      *
  424.      * @return void 
  425.      */
  426.     public function rollbackChangeset()
  427.     {
  428.         $this->inChangeset = false;
  429.         $this->inConflict  = false;
  430.  
  431.         if (empty($this->changeset=== false{
  432.             if (PHP_CODESNIFFER_VERBOSITY > 1{
  433.                 $bt debug_backtrace();
  434.                 if ($bt[1]['class'=== 'PHP_CodeSniffer\Fixer'{
  435.                     $sniff $bt[2]['class'];
  436.                     $line  $bt[1]['line'];
  437.                 else {
  438.                     $sniff $bt[1]['class'];
  439.                     $line  $bt[0]['line'];
  440.                 }
  441.  
  442.                 $numChanges count($this->changeset);
  443.  
  444.                 @ob_end_clean();
  445.                 echo "\t\tR: $sniff (line $line) rolled back the changeset ($numChanges changes)".PHP_EOL;
  446.                 echo "\t=> Changeset rolled back".PHP_EOL;
  447.                 ob_start();
  448.             }
  449.  
  450.             $this->changeset = array();
  451.         }//end if
  452.  
  453.     }//end rollbackChangeset()
  454.  
  455.  
  456.     /**
  457.      * Replace the entire contents of a token.
  458.      *
  459.      * @param int    $stackPtr The position of the token in the token stack.
  460.      * @param string $content  The new content of the token.
  461.      *
  462.      * @return bool If the change was accepted.
  463.      */
  464.     public function replaceToken($stackPtr$content)
  465.     {
  466.         if ($this->inConflict === true{
  467.             return false;
  468.         }
  469.  
  470.         if ($this->inChangeset === false
  471.             && isset($this->fixedTokens[$stackPtr]=== true
  472.         {
  473.             $indent "\t";
  474.             if (empty($this->changeset=== false{
  475.                 $indent .= "\t";
  476.             }
  477.  
  478.             if (PHP_CODESNIFFER_VERBOSITY > 1{
  479.                 @ob_end_clean();
  480.                 echo "$indent* token $stackPtr has already been modified, skipping *".PHP_EOL;
  481.                 ob_start();
  482.             }
  483.  
  484.             return false;
  485.         }
  486.  
  487.         if (PHP_CODESNIFFER_VERBOSITY > 1{
  488.             $bt debug_backtrace();
  489.             if ($bt[1]['class'=== 'PHP_CodeSniffer\Fixer'{
  490.                 $sniff $bt[2]['class'];
  491.                 $line  $bt[1]['line'];
  492.             else {
  493.                 $sniff $bt[1]['class'];
  494.                 $line  $bt[0]['line'];
  495.             }
  496.  
  497.             $tokens     $this->currentFile->getTokens();
  498.             $type       $tokens[$stackPtr]['type'];
  499.             $oldContent = Common::prepareForOutput($this->tokens[$stackPtr]);
  500.             $newContent = Common::prepareForOutput($content);
  501.             if (trim($this->tokens[$stackPtr]=== '' && isset($this->tokens[($stackPtr + 1)]=== true{
  502.                 // Add some context for whitespace only changes.
  503.                 $append      = Common::prepareForOutput($this->tokens[($stackPtr + 1)]);
  504.                 $oldContent .= $append;
  505.                 $newContent .= $append;
  506.             }
  507.         }//end if
  508.  
  509.         if ($this->inChangeset === true{
  510.             $this->changeset[$stackPtr$content;
  511.  
  512.             if (PHP_CODESNIFFER_VERBOSITY > 1{
  513.                 @ob_end_clean();
  514.                 echo "\t\tQ: $sniff (line $line) replaced token $stackPtr ($type) \"$oldContent\" => \"$newContent\"".PHP_EOL;
  515.                 ob_start();
  516.             }
  517.  
  518.             return true;
  519.         }
  520.  
  521.         if (isset($this->oldTokenValues[$stackPtr]=== false{
  522.             $this->oldTokenValues[$stackPtr= array(
  523.                                                 'curr' => $content,
  524.                                                 'prev' => $this->tokens[$stackPtr],
  525.                                                 'loop' => $this->loops,
  526.                                                );
  527.         else {
  528.             if ($this->oldTokenValues[$stackPtr]['prev'=== $content
  529.                 && $this->oldTokenValues[$stackPtr]['loop'=== ($this->loops - 1)
  530.             {
  531.                 if (PHP_CODESNIFFER_VERBOSITY > 1{
  532.                     $indent "\t";
  533.                     if (empty($this->changeset=== false{
  534.                         $indent .= "\t";
  535.                     }
  536.  
  537.                     $loop $this->oldTokenValues[$stackPtr]['loop'];
  538.  
  539.                     @ob_end_clean();
  540.                     echo "$indent**** $sniff (line $line) has possible conflict with another sniff on loop $loop; caused by the following change ****".PHP_EOL;
  541.                     echo "$indent**** replaced token $stackPtr ($type) \"$oldContent\" => \"$newContent\" ****".PHP_EOL;
  542.                 }
  543.  
  544.                 if ($this->oldTokenValues[$stackPtr]['loop'>= ($this->loops - 1)) {
  545.                     $this->inConflict = true;
  546.                     if (PHP_CODESNIFFER_VERBOSITY > 1{
  547.                         echo "$indent**** ignoring all changes until next loop ****".PHP_EOL;
  548.                     }
  549.                 }
  550.  
  551.                 if (PHP_CODESNIFFER_VERBOSITY > 1{
  552.                     ob_start();
  553.                 }
  554.  
  555.                 return false;
  556.             }//end if
  557.  
  558.             $this->oldTokenValues[$stackPtr]['prev'$this->oldTokenValues[$stackPtr]['curr'];
  559.             $this->oldTokenValues[$stackPtr]['curr'$content;
  560.             $this->oldTokenValues[$stackPtr]['loop'$this->loops;
  561.         }//end if
  562.  
  563.         $this->fixedTokens[$stackPtr$this->tokens[$stackPtr];
  564.         $this->tokens[$stackPtr]      $content;
  565.         $this->numFixes++;
  566.  
  567.         if (PHP_CODESNIFFER_VERBOSITY > 1{
  568.             $indent "\t";
  569.             if (empty($this->changeset=== false{
  570.                 $indent .= "\tA: ";
  571.             }
  572.  
  573.             if (ob_get_level(> 0{
  574.                 ob_end_clean();
  575.             }
  576.  
  577.             echo "$indent$sniff (line $line) replaced token $stackPtr ($type) \"$oldContent\" => \"$newContent\"".PHP_EOL;
  578.             ob_start();
  579.         }
  580.  
  581.         return true;
  582.  
  583.     }//end replaceToken()
  584.  
  585.  
  586.     /**
  587.      * Reverts the previous fix made to a token.
  588.      *
  589.      * @param int $stackPtr The position of the token in the token stack.
  590.      *
  591.      * @return bool If a change was reverted.
  592.      */
  593.     public function revertToken($stackPtr)
  594.     {
  595.         if (isset($this->fixedTokens[$stackPtr]=== false{
  596.             return false;
  597.         }
  598.  
  599.         if (PHP_CODESNIFFER_VERBOSITY > 1{
  600.             $bt debug_backtrace();
  601.             if ($bt[1]['class'=== 'PHP_CodeSniffer\Fixer'{
  602.                 $sniff $bt[2]['class'];
  603.                 $line  $bt[1]['line'];
  604.             else {
  605.                 $sniff $bt[1]['class'];
  606.                 $line  $bt[0]['line'];
  607.             }
  608.  
  609.             $tokens     $this->currentFile->getTokens();
  610.             $type       $tokens[$stackPtr]['type'];
  611.             $oldContent = Common::prepareForOutput($this->tokens[$stackPtr]);
  612.             $newContent = Common::prepareForOutput($this->fixedTokens[$stackPtr]);
  613.             if (trim($this->tokens[$stackPtr]=== '' && isset($tokens[($stackPtr + 1)]=== true{
  614.                 // Add some context for whitespace only changes.
  615.                 $append      = Common::prepareForOutput($this->tokens[($stackPtr + 1)]);
  616.                 $oldContent .= $append;
  617.                 $newContent .= $append;
  618.             }
  619.         }//end if
  620.  
  621.         $this->tokens[$stackPtr$this->fixedTokens[$stackPtr];
  622.         unset($this->fixedTokens[$stackPtr]);
  623.         $this->numFixes--;
  624.  
  625.         if (PHP_CODESNIFFER_VERBOSITY > 1{
  626.             $indent "\t";
  627.             if (empty($this->changeset=== false{
  628.                 $indent .= "\tR: ";
  629.             }
  630.  
  631.             @ob_end_clean();
  632.             echo "$indent$sniff (line $line) reverted token $stackPtr ($type) \"$oldContent\" => \"$newContent\"".PHP_EOL;
  633.             ob_start();
  634.         }
  635.  
  636.         return true;
  637.  
  638.     }//end revertToken()
  639.  
  640.  
  641.     /**
  642.      * Replace the content of a token with a part of its current content.
  643.      *
  644.      * @param int $stackPtr The position of the token in the token stack.
  645.      * @param int $start    The first character to keep.
  646.      * @param int $length   The number of chacters to keep. If NULL, the content of
  647.      *                       the token from $start to the end of the content is kept.
  648.      *
  649.      * @return bool If the change was accepted.
  650.      */
  651.     public function substrToken($stackPtr$start$length=null)
  652.     {
  653.         $current $this->getTokenContent($stackPtr);
  654.  
  655.         if ($length === null{
  656.             $newContent substr($current$start);
  657.         else {
  658.             $newContent substr($current$start$length);
  659.         }
  660.  
  661.         return $this->replaceToken($stackPtr$newContent);
  662.  
  663.     }//end substrToken()
  664.  
  665.  
  666.     /**
  667.      * Adds a newline to end of a token's content.
  668.      *
  669.      * @param int $stackPtr The position of the token in the token stack.
  670.      *
  671.      * @return bool If the change was accepted.
  672.      */
  673.     public function addNewline($stackPtr)
  674.     {
  675.         $current $this->getTokenContent($stackPtr);
  676.         return $this->replaceToken($stackPtr$current.$this->currentFile->eolChar);
  677.  
  678.     }//end addNewline()
  679.  
  680.  
  681.     /**
  682.      * Adds a newline to the start of a token's content.
  683.      *
  684.      * @param int $stackPtr The position of the token in the token stack.
  685.      *
  686.      * @return bool If the change was accepted.
  687.      */
  688.     public function addNewlineBefore($stackPtr)
  689.     {
  690.         $current $this->getTokenContent($stackPtr);
  691.         return $this->replaceToken($stackPtr$this->currentFile->eolChar.$current);
  692.  
  693.     }//end addNewlineBefore()
  694.  
  695.  
  696.     /**
  697.      * Adds content to the end of a token's current content.
  698.      *
  699.      * @param int    $stackPtr The position of the token in the token stack.
  700.      * @param string $content  The content to add.
  701.      *
  702.      * @return bool If the change was accepted.
  703.      */
  704.     public function addContent($stackPtr$content)
  705.     {
  706.         $current $this->getTokenContent($stackPtr);
  707.         return $this->replaceToken($stackPtr$current.$content);
  708.  
  709.     }//end addContent()
  710.  
  711.  
  712.     /**
  713.      * Adds content to the start of a token's current content.
  714.      *
  715.      * @param int    $stackPtr The position of the token in the token stack.
  716.      * @param string $content  The content to add.
  717.      *
  718.      * @return bool If the change was accepted.
  719.      */
  720.     public function addContentBefore($stackPtr$content)
  721.     {
  722.         $current $this->getTokenContent($stackPtr);
  723.         return $this->replaceToken($stackPtr$content.$current);
  724.  
  725.     }//end addContentBefore()
  726.  
  727.  
  728. }//end class

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