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.                 @ob_end_clean();
  207.                 echo "\t*** Reached maximum number of loops with $this->numFixes violations left unfixed ***".PHP_EOL;
  208.                 ob_start();
  209.             }
  210.  
  211.             return false;
  212.         }
  213.  
  214.         return true;
  215.  
  216.     }//end fixFile()
  217.  
  218.  
  219.     /**
  220.      * Generates a text diff of the original file and the new content.
  221.      *
  222.      * @param string  $filePath Optional file path to diff the file against.
  223.      *                           If not specified, the original version of the
  224.      *                           file will be used.
  225.      * @param boolean $colors   Print colored output or not.
  226.      *
  227.      * @return string 
  228.      */
  229.     public function generateDiff($filePath=null$colors=true)
  230.     {
  231.         if ($filePath === null{
  232.             $filePath $this->currentFile->getFilename();
  233.         }
  234.  
  235.         $cwd getcwd().DIRECTORY_SEPARATOR;
  236.         if (strpos($filePath$cwd=== 0{
  237.             $filename substr($filePathstrlen($cwd));
  238.         else {
  239.             $filename $filePath;
  240.         }
  241.  
  242.         $contents $this->getContents();
  243.  
  244.         $tempName  tempnam(sys_get_temp_dir()'phpcs-fixer');
  245.         $fixedFile fopen($tempName'w');
  246.         fwrite($fixedFile$contents);
  247.  
  248.         // We must use something like shell_exec() because whitespace at the end
  249.         // of lines is critical to diff files.
  250.         $filename escapeshellarg($filename);
  251.         $cmd      = "diff -u -L$filename -LPHP_CodeSniffer $filename \"$tempName\"";
  252.  
  253.         $diff shell_exec($cmd);
  254.  
  255.         fclose($fixedFile);
  256.         if (is_file($tempName=== true{
  257.             unlink($tempName);
  258.         }
  259.  
  260.         if ($colors === false{
  261.             return $diff;
  262.         }
  263.  
  264.         $diffLines explode(PHP_EOL$diff);
  265.         if (count($diffLines=== 1{
  266.             // Seems to be required for cygwin.
  267.             $diffLines explode("\n"$diff);
  268.         }
  269.  
  270.         $diff = array();
  271.         foreach ($diffLines as $line{
  272.             if (isset($line[0]=== true{
  273.                 switch ($line[0]{
  274.                 case '-':
  275.                     $diff[= "\033[31m$line\033[0m";
  276.                     break;
  277.                 case '+':
  278.                     $diff[= "\033[32m$line\033[0m";
  279.                     break;
  280.                 default:
  281.                     $diff[$line;
  282.                 }
  283.             }
  284.         }
  285.  
  286.         $diff implode(PHP_EOL$diff);
  287.  
  288.         return $diff;
  289.  
  290.     }//end generateDiff()
  291.  
  292.  
  293.     /**
  294.      * Get a count of fixes that have been performed on the file.
  295.      *
  296.      * This value is reset every time a new file is started, or an existing
  297.      * file is restarted.
  298.      *
  299.      * @return int 
  300.      */
  301.     public function getFixCount()
  302.     {
  303.         return $this->numFixes;
  304.  
  305.     }//end getFixCount()
  306.  
  307.  
  308.     /**
  309.      * Get the current content of the file, as a string.
  310.      *
  311.      * @return string 
  312.      */
  313.     public function getContents()
  314.     {
  315.         $contents implode($this->tokens);
  316.         return $contents;
  317.  
  318.     }//end getContents()
  319.  
  320.  
  321.     /**
  322.      * Get the current fixed content of a token.
  323.      *
  324.      * This function takes changesets into account so should be used
  325.      * instead of directly accessing the token array.
  326.      *
  327.      * @param int $stackPtr The position of the token in the token stack.
  328.      *
  329.      * @return string 
  330.      */
  331.     public function getTokenContent($stackPtr)
  332.     {
  333.         if ($this->inChangeset === true
  334.             && isset($this->changeset[$stackPtr]=== true
  335.         {
  336.             return $this->changeset[$stackPtr];
  337.         else {
  338.             return $this->tokens[$stackPtr];
  339.         }
  340.  
  341.     }//end getTokenContent()
  342.  
  343.  
  344.     /**
  345.      * Start recording actions for a changeset.
  346.      *
  347.      * @return void 
  348.      */
  349.     public function beginChangeset()
  350.     {
  351.         if ($this->inConflict === true{
  352.             return false;
  353.         }
  354.  
  355.         if (PHP_CODESNIFFER_VERBOSITY > 1{
  356.             $bt    debug_backtrace();
  357.             $sniff $bt[1]['class'];
  358.             $line  $bt[0]['line'];
  359.  
  360.             @ob_end_clean();
  361.             echo "\t=> Changeset started by $sniff (line $line)".PHP_EOL;
  362.             ob_start();
  363.         }
  364.  
  365.         $this->changeset   = array();
  366.         $this->inChangeset = true;
  367.  
  368.     }//end beginChangeset()
  369.  
  370.  
  371.     /**
  372.      * Stop recording actions for a changeset, and apply logged changes.
  373.      *
  374.      * @return boolean 
  375.      */
  376.     public function endChangeset()
  377.     {
  378.         if ($this->inConflict === true{
  379.             return false;
  380.         }
  381.  
  382.         $this->inChangeset = false;
  383.  
  384.         $success = true;
  385.         $applied = array();
  386.         foreach ($this->changeset as $stackPtr => $content{
  387.             $success $this->replaceToken($stackPtr$content);
  388.             if ($success === false{
  389.                 break;
  390.             else {
  391.                 $applied[$stackPtr;
  392.             }
  393.         }
  394.  
  395.         if ($success === false{
  396.             // Rolling back all changes.
  397.             foreach ($applied as $stackPtr{
  398.                 $this->revertToken($stackPtr);
  399.             }
  400.  
  401.             if (PHP_CODESNIFFER_VERBOSITY > 1{
  402.                 @ob_end_clean();
  403.                 echo "\t=> Changeset failed to apply".PHP_EOL;
  404.                 ob_start();
  405.             }
  406.         else if (PHP_CODESNIFFER_VERBOSITY > 1{
  407.             $fixes count($this->changeset);
  408.             @ob_end_clean();
  409.             echo "\t=> Changeset ended: $fixes changes applied".PHP_EOL;
  410.             ob_start();
  411.         }
  412.  
  413.         $this->changeset = array();
  414.  
  415.     }//end endChangeset()
  416.  
  417.  
  418.     /**
  419.      * Stop recording actions for a changeset, and discard logged changes.
  420.      *
  421.      * @return void 
  422.      */
  423.     public function rollbackChangeset()
  424.     {
  425.         $this->inChangeset = false;
  426.         $this->inConflict  = false;
  427.  
  428.         if (empty($this->changeset=== false{
  429.             if (PHP_CODESNIFFER_VERBOSITY > 1{
  430.                 $bt debug_backtrace();
  431.                 if ($bt[1]['class'=== 'PHP_CodeSniffer\Fixer'{
  432.                     $sniff $bt[2]['class'];
  433.                     $line  $bt[1]['line'];
  434.                 else {
  435.                     $sniff $bt[1]['class'];
  436.                     $line  $bt[0]['line'];
  437.                 }
  438.  
  439.                 $numChanges count($this->changeset);
  440.  
  441.                 @ob_end_clean();
  442.                 echo "\t\tR: $sniff (line $line) rolled back the changeset ($numChanges changes)".PHP_EOL;
  443.                 echo "\t=> Changeset rolled back".PHP_EOL;
  444.                 ob_start();
  445.             }
  446.  
  447.             $this->changeset = array();
  448.         }//end if
  449.  
  450.     }//end rollbackChangeset()
  451.  
  452.  
  453.     /**
  454.      * Replace the entire contents of a token.
  455.      *
  456.      * @param int    $stackPtr The position of the token in the token stack.
  457.      * @param string $content  The new content of the token.
  458.      *
  459.      * @return bool If the change was accepted.
  460.      */
  461.     public function replaceToken($stackPtr$content)
  462.     {
  463.         if ($this->inConflict === true{
  464.             return false;
  465.         }
  466.  
  467.         if ($this->inChangeset === false
  468.             && isset($this->fixedTokens[$stackPtr]=== true
  469.         {
  470.             $indent "\t";
  471.             if (empty($this->changeset=== false{
  472.                 $indent .= "\t";
  473.             }
  474.  
  475.             if (PHP_CODESNIFFER_VERBOSITY > 1{
  476.                 @ob_end_clean();
  477.                 echo "$indent* token $stackPtr has already been modified, skipping *".PHP_EOL;
  478.                 ob_start();
  479.             }
  480.  
  481.             return false;
  482.         }
  483.  
  484.         if (PHP_CODESNIFFER_VERBOSITY > 1{
  485.             $bt debug_backtrace();
  486.             if ($bt[1]['class'=== 'PHP_CodeSniffer\Fixer'{
  487.                 $sniff $bt[2]['class'];
  488.                 $line  $bt[1]['line'];
  489.             else {
  490.                 $sniff $bt[1]['class'];
  491.                 $line  $bt[0]['line'];
  492.             }
  493.  
  494.             $tokens     $this->currentFile->getTokens();
  495.             $type       $tokens[$stackPtr]['type'];
  496.             $oldContent = Common::prepareForOutput($this->tokens[$stackPtr]);
  497.             $newContent = Common::prepareForOutput($content);
  498.             if (trim($this->tokens[$stackPtr]=== '' && isset($this->tokens[($stackPtr + 1)]=== true{
  499.                 // Add some context for whitespace only changes.
  500.                 $append      = Common::prepareForOutput($this->tokens[($stackPtr + 1)]);
  501.                 $oldContent .= $append;
  502.                 $newContent .= $append;
  503.             }
  504.         }//end if
  505.  
  506.         if ($this->inChangeset === true{
  507.             $this->changeset[$stackPtr$content;
  508.  
  509.             if (PHP_CODESNIFFER_VERBOSITY > 1{
  510.                 @ob_end_clean();
  511.                 echo "\t\tQ: $sniff (line $line) replaced token $stackPtr ($type) \"$oldContent\" => \"$newContent\"".PHP_EOL;
  512.                 ob_start();
  513.             }
  514.  
  515.             return true;
  516.         }
  517.  
  518.         if (isset($this->oldTokenValues[$stackPtr]=== false{
  519.             $this->oldTokenValues[$stackPtr= array(
  520.                                                 'curr' => $content,
  521.                                                 'prev' => $this->tokens[$stackPtr],
  522.                                                 'loop' => $this->loops,
  523.                                                );
  524.         else {
  525.             if ($this->oldTokenValues[$stackPtr]['prev'=== $content
  526.                 && $this->oldTokenValues[$stackPtr]['loop'=== ($this->loops - 1)
  527.             {
  528.                 if (PHP_CODESNIFFER_VERBOSITY > 1{
  529.                     $indent "\t";
  530.                     if (empty($this->changeset=== false{
  531.                         $indent .= "\t";
  532.                     }
  533.  
  534.                     $loop $this->oldTokenValues[$stackPtr]['loop'];
  535.  
  536.                     @ob_end_clean();
  537.                     echo "$indent**** $sniff (line $line) has possible conflict with another sniff on loop $loop; caused by the following change ****".PHP_EOL;
  538.                     echo "$indent**** replaced token $stackPtr ($type) \"$oldContent\" => \"$newContent\" ****".PHP_EOL;
  539.                 }
  540.  
  541.                 if ($this->oldTokenValues[$stackPtr]['loop'>= ($this->loops - 1)) {
  542.                     $this->inConflict = true;
  543.                     if (PHP_CODESNIFFER_VERBOSITY > 1{
  544.                         echo "$indent**** ignoring all changes until next loop ****".PHP_EOL;
  545.                     }
  546.                 }
  547.  
  548.                 if (PHP_CODESNIFFER_VERBOSITY > 1{
  549.                     ob_start();
  550.                 }
  551.  
  552.                 return false;
  553.             }//end if
  554.  
  555.             $this->oldTokenValues[$stackPtr]['prev'$this->oldTokenValues[$stackPtr]['curr'];
  556.             $this->oldTokenValues[$stackPtr]['curr'$content;
  557.             $this->oldTokenValues[$stackPtr]['loop'$this->loops;
  558.         }//end if
  559.  
  560.         $this->fixedTokens[$stackPtr$this->tokens[$stackPtr];
  561.         $this->tokens[$stackPtr]      $content;
  562.         $this->numFixes++;
  563.  
  564.         if (PHP_CODESNIFFER_VERBOSITY > 1{
  565.             $indent "\t";
  566.             if (empty($this->changeset=== false{
  567.                 $indent .= "\tA: ";
  568.             }
  569.  
  570.             if (ob_get_level(> 0{
  571.                 ob_end_clean();
  572.             }
  573.  
  574.             echo "$indent$sniff (line $line) replaced token $stackPtr ($type) \"$oldContent\" => \"$newContent\"".PHP_EOL;
  575.             ob_start();
  576.         }
  577.  
  578.         return true;
  579.  
  580.     }//end replaceToken()
  581.  
  582.  
  583.     /**
  584.      * Reverts the previous fix made to a token.
  585.      *
  586.      * @param int $stackPtr The position of the token in the token stack.
  587.      *
  588.      * @return bool If a change was reverted.
  589.      */
  590.     public function revertToken($stackPtr)
  591.     {
  592.         if (isset($this->fixedTokens[$stackPtr]=== false{
  593.             return false;
  594.         }
  595.  
  596.         if (PHP_CODESNIFFER_VERBOSITY > 1{
  597.             $bt debug_backtrace();
  598.             if ($bt[1]['class'=== 'PHP_CodeSniffer\Fixer'{
  599.                 $sniff $bt[2]['class'];
  600.                 $line  $bt[1]['line'];
  601.             else {
  602.                 $sniff $bt[1]['class'];
  603.                 $line  $bt[0]['line'];
  604.             }
  605.  
  606.             $tokens     $this->currentFile->getTokens();
  607.             $type       $tokens[$stackPtr]['type'];
  608.             $oldContent = Common::prepareForOutput($this->tokens[$stackPtr]);
  609.             $newContent = Common::prepareForOutput($this->fixedTokens[$stackPtr]);
  610.             if (trim($this->tokens[$stackPtr]=== '' && isset($tokens[($stackPtr + 1)]=== true{
  611.                 // Add some context for whitespace only changes.
  612.                 $append      = Common::prepareForOutput($this->tokens[($stackPtr + 1)]);
  613.                 $oldContent .= $append;
  614.                 $newContent .= $append;
  615.             }
  616.         }//end if
  617.  
  618.         $this->tokens[$stackPtr$this->fixedTokens[$stackPtr];
  619.         unset($this->fixedTokens[$stackPtr]);
  620.         $this->numFixes--;
  621.  
  622.         if (PHP_CODESNIFFER_VERBOSITY > 1{
  623.             $indent "\t";
  624.             if (empty($this->changeset=== false{
  625.                 $indent .= "\tR: ";
  626.             }
  627.  
  628.             @ob_end_clean();
  629.             echo "$indent$sniff (line $line) reverted token $stackPtr ($type) \"$oldContent\" => \"$newContent\"".PHP_EOL;
  630.             ob_start();
  631.         }
  632.  
  633.         return true;
  634.  
  635.     }//end revertToken()
  636.  
  637.  
  638.     /**
  639.      * Replace the content of a token with a part of its current content.
  640.      *
  641.      * @param int $stackPtr The position of the token in the token stack.
  642.      * @param int $start    The first character to keep.
  643.      * @param int $length   The number of chacters to keep. If NULL, the content of
  644.      *                       the token from $start to the end of the content is kept.
  645.      *
  646.      * @return bool If the change was accepted.
  647.      */
  648.     public function substrToken($stackPtr$start$length=null)
  649.     {
  650.         $current $this->getTokenContent($stackPtr);
  651.  
  652.         if ($length === null{
  653.             $newContent substr($current$start);
  654.         else {
  655.             $newContent substr($current$start$length);
  656.         }
  657.  
  658.         return $this->replaceToken($stackPtr$newContent);
  659.  
  660.     }//end substrToken()
  661.  
  662.  
  663.     /**
  664.      * Adds a newline to end of a token's content.
  665.      *
  666.      * @param int $stackPtr The position of the token in the token stack.
  667.      *
  668.      * @return bool If the change was accepted.
  669.      */
  670.     public function addNewline($stackPtr)
  671.     {
  672.         $current $this->getTokenContent($stackPtr);
  673.         return $this->replaceToken($stackPtr$current.$this->currentFile->eolChar);
  674.  
  675.     }//end addNewline()
  676.  
  677.  
  678.     /**
  679.      * Adds a newline to the start of a token's content.
  680.      *
  681.      * @param int $stackPtr The position of the token in the token stack.
  682.      *
  683.      * @return bool If the change was accepted.
  684.      */
  685.     public function addNewlineBefore($stackPtr)
  686.     {
  687.         $current $this->getTokenContent($stackPtr);
  688.         return $this->replaceToken($stackPtr$this->currentFile->eolChar.$current);
  689.  
  690.     }//end addNewlineBefore()
  691.  
  692.  
  693.     /**
  694.      * Adds content to the end of a token's current content.
  695.      *
  696.      * @param int    $stackPtr The position of the token in the token stack.
  697.      * @param string $content  The content to add.
  698.      *
  699.      * @return bool If the change was accepted.
  700.      */
  701.     public function addContent($stackPtr$content)
  702.     {
  703.         $current $this->getTokenContent($stackPtr);
  704.         return $this->replaceToken($stackPtr$current.$content);
  705.  
  706.     }//end addContent()
  707.  
  708.  
  709.     /**
  710.      * Adds content to the start of a token's current content.
  711.      *
  712.      * @param int    $stackPtr The position of the token in the token stack.
  713.      * @param string $content  The content to add.
  714.      *
  715.      * @return bool If the change was accepted.
  716.      */
  717.     public function addContentBefore($stackPtr$content)
  718.     {
  719.         $current $this->getTokenContent($stackPtr);
  720.         return $this->replaceToken($stackPtr$content.$current);
  721.  
  722.     }//end addContentBefore()
  723.  
  724.  
  725. }//end class

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