gluon-web-remote

Web remote Administration for big size of gluon routers
git clone git://archive.git.mtrnord.blog/MTRNord/gluon-web-remote.git
Log | Files | Refs | README

Stream.php (16638B)


      1 <?php
      2 /*
      3  * This file is part of the PHP_TokenStream package.
      4  *
      5  * (c) Sebastian Bergmann <sebastian@phpunit.de>
      6  *
      7  * For the full copyright and license information, please view the LICENSE
      8  * file that was distributed with this source code.
      9  */
     10 
     11 /**
     12  * A stream of PHP tokens.
     13  *
     14  * @author    Sebastian Bergmann <sebastian@phpunit.de>
     15  * @copyright Sebastian Bergmann <sebastian@phpunit.de>
     16  * @license   http://www.opensource.org/licenses/BSD-3-Clause  The BSD 3-Clause License
     17  * @link      http://github.com/sebastianbergmann/php-token-stream/tree
     18  * @since     Class available since Release 1.0.0
     19  */
     20 class PHP_Token_Stream implements ArrayAccess, Countable, SeekableIterator
     21 {
     22     /**
     23      * @var array
     24      */
     25     protected static $customTokens = array(
     26         '(' => 'PHP_Token_OPEN_BRACKET',
     27         ')' => 'PHP_Token_CLOSE_BRACKET',
     28         '[' => 'PHP_Token_OPEN_SQUARE',
     29         ']' => 'PHP_Token_CLOSE_SQUARE',
     30         '{' => 'PHP_Token_OPEN_CURLY',
     31         '}' => 'PHP_Token_CLOSE_CURLY',
     32         ';' => 'PHP_Token_SEMICOLON',
     33         '.' => 'PHP_Token_DOT',
     34         ',' => 'PHP_Token_COMMA',
     35         '=' => 'PHP_Token_EQUAL',
     36         '<' => 'PHP_Token_LT',
     37         '>' => 'PHP_Token_GT',
     38         '+' => 'PHP_Token_PLUS',
     39         '-' => 'PHP_Token_MINUS',
     40         '*' => 'PHP_Token_MULT',
     41         '/' => 'PHP_Token_DIV',
     42         '?' => 'PHP_Token_QUESTION_MARK',
     43         '!' => 'PHP_Token_EXCLAMATION_MARK',
     44         ':' => 'PHP_Token_COLON',
     45         '"' => 'PHP_Token_DOUBLE_QUOTES',
     46         '@' => 'PHP_Token_AT',
     47         '&' => 'PHP_Token_AMPERSAND',
     48         '%' => 'PHP_Token_PERCENT',
     49         '|' => 'PHP_Token_PIPE',
     50         '$' => 'PHP_Token_DOLLAR',
     51         '^' => 'PHP_Token_CARET',
     52         '~' => 'PHP_Token_TILDE',
     53         '`' => 'PHP_Token_BACKTICK'
     54     );
     55 
     56     /**
     57      * @var string
     58      */
     59     protected $filename;
     60 
     61     /**
     62      * @var array
     63      */
     64     protected $tokens = array();
     65 
     66     /**
     67      * @var integer
     68      */
     69     protected $position = 0;
     70 
     71     /**
     72      * @var array
     73      */
     74     protected $linesOfCode = array('loc' => 0, 'cloc' => 0, 'ncloc' => 0);
     75 
     76     /**
     77      * @var array
     78      */
     79     protected $classes;
     80 
     81     /**
     82      * @var array
     83      */
     84     protected $functions;
     85 
     86     /**
     87      * @var array
     88      */
     89     protected $includes;
     90 
     91     /**
     92      * @var array
     93      */
     94     protected $interfaces;
     95 
     96     /**
     97      * @var array
     98      */
     99     protected $traits;
    100 
    101     /**
    102      * @var array
    103      */
    104     protected $lineToFunctionMap = array();
    105 
    106     /**
    107      * Constructor.
    108      *
    109      * @param string $sourceCode
    110      */
    111     public function __construct($sourceCode)
    112     {
    113         if (is_file($sourceCode)) {
    114             $this->filename = $sourceCode;
    115             $sourceCode     = file_get_contents($sourceCode);
    116         }
    117 
    118         $this->scan($sourceCode);
    119     }
    120 
    121     /**
    122      * Destructor.
    123      */
    124     public function __destruct()
    125     {
    126         $this->tokens = array();
    127     }
    128 
    129     /**
    130      * @return string
    131      */
    132     public function __toString()
    133     {
    134         $buffer = '';
    135 
    136         foreach ($this as $token) {
    137             $buffer .= $token;
    138         }
    139 
    140         return $buffer;
    141     }
    142 
    143     /**
    144      * @return string
    145      * @since  Method available since Release 1.1.0
    146      */
    147     public function getFilename()
    148     {
    149         return $this->filename;
    150     }
    151 
    152     /**
    153      * Scans the source for sequences of characters and converts them into a
    154      * stream of tokens.
    155      *
    156      * @param string $sourceCode
    157      */
    158     protected function scan($sourceCode)
    159     {
    160         $line      = 1;
    161         $tokens    = token_get_all($sourceCode);
    162         $numTokens = count($tokens);
    163 
    164         $lastNonWhitespaceTokenWasDoubleColon = false;
    165 
    166         for ($i = 0; $i < $numTokens; ++$i) {
    167             $token = $tokens[$i];
    168             unset($tokens[$i]);
    169 
    170             if (is_array($token)) {
    171                 $name = substr(token_name($token[0]), 2);
    172                 $text = $token[1];
    173 
    174                 if ($lastNonWhitespaceTokenWasDoubleColon && $name == 'CLASS') {
    175                     $name = 'CLASS_NAME_CONSTANT';
    176                 }
    177 
    178                 $tokenClass = 'PHP_Token_' . $name;
    179             } else {
    180                 $text       = $token;
    181                 $tokenClass = self::$customTokens[$token];
    182             }
    183 
    184             $this->tokens[] = new $tokenClass($text, $line, $this, $i);
    185             $lines          = substr_count($text, "\n");
    186             $line          += $lines;
    187 
    188             if ($tokenClass == 'PHP_Token_HALT_COMPILER') {
    189                 break;
    190             } elseif ($tokenClass == 'PHP_Token_COMMENT' ||
    191                 $tokenClass == 'PHP_Token_DOC_COMMENT') {
    192                 $this->linesOfCode['cloc'] += $lines + 1;
    193             }
    194 
    195             if ($name == 'DOUBLE_COLON') {
    196                 $lastNonWhitespaceTokenWasDoubleColon = true;
    197             } elseif ($name != 'WHITESPACE') {
    198                 $lastNonWhitespaceTokenWasDoubleColon = false;
    199             }
    200         }
    201 
    202         $this->linesOfCode['loc']   = substr_count($sourceCode, "\n");
    203         $this->linesOfCode['ncloc'] = $this->linesOfCode['loc'] -
    204                                       $this->linesOfCode['cloc'];
    205     }
    206 
    207     /**
    208      * @return integer
    209      */
    210     public function count()
    211     {
    212         return count($this->tokens);
    213     }
    214 
    215     /**
    216      * @return PHP_Token[]
    217      */
    218     public function tokens()
    219     {
    220         return $this->tokens;
    221     }
    222 
    223     /**
    224      * @return array
    225      */
    226     public function getClasses()
    227     {
    228         if ($this->classes !== null) {
    229             return $this->classes;
    230         }
    231 
    232         $this->parse();
    233 
    234         return $this->classes;
    235     }
    236 
    237     /**
    238      * @return array
    239      */
    240     public function getFunctions()
    241     {
    242         if ($this->functions !== null) {
    243             return $this->functions;
    244         }
    245 
    246         $this->parse();
    247 
    248         return $this->functions;
    249     }
    250 
    251     /**
    252      * @return array
    253      */
    254     public function getInterfaces()
    255     {
    256         if ($this->interfaces !== null) {
    257             return $this->interfaces;
    258         }
    259 
    260         $this->parse();
    261 
    262         return $this->interfaces;
    263     }
    264 
    265     /**
    266      * @return array
    267      * @since  Method available since Release 1.1.0
    268      */
    269     public function getTraits()
    270     {
    271         if ($this->traits !== null) {
    272             return $this->traits;
    273         }
    274 
    275         $this->parse();
    276 
    277         return $this->traits;
    278     }
    279 
    280     /**
    281      * Gets the names of all files that have been included
    282      * using include(), include_once(), require() or require_once().
    283      *
    284      * Parameter $categorize set to TRUE causing this function to return a
    285      * multi-dimensional array with categories in the keys of the first dimension
    286      * and constants and their values in the second dimension.
    287      *
    288      * Parameter $category allow to filter following specific inclusion type
    289      *
    290      * @param bool   $categorize OPTIONAL
    291      * @param string $category   OPTIONAL Either 'require_once', 'require',
    292      *                                           'include_once', 'include'.
    293      * @return array
    294      * @since  Method available since Release 1.1.0
    295      */
    296     public function getIncludes($categorize = false, $category = null)
    297     {
    298         if ($this->includes === null) {
    299             $this->includes = array(
    300               'require_once' => array(),
    301               'require'      => array(),
    302               'include_once' => array(),
    303               'include'      => array()
    304             );
    305 
    306             foreach ($this->tokens as $token) {
    307                 switch (get_class($token)) {
    308                     case 'PHP_Token_REQUIRE_ONCE':
    309                     case 'PHP_Token_REQUIRE':
    310                     case 'PHP_Token_INCLUDE_ONCE':
    311                     case 'PHP_Token_INCLUDE':
    312                         $this->includes[$token->getType()][] = $token->getName();
    313                         break;
    314                 }
    315             }
    316         }
    317 
    318         if (isset($this->includes[$category])) {
    319             $includes = $this->includes[$category];
    320         } elseif ($categorize === false) {
    321             $includes = array_merge(
    322                 $this->includes['require_once'],
    323                 $this->includes['require'],
    324                 $this->includes['include_once'],
    325                 $this->includes['include']
    326             );
    327         } else {
    328             $includes = $this->includes;
    329         }
    330 
    331         return $includes;
    332     }
    333 
    334     /**
    335      * Returns the name of the function or method a line belongs to.
    336      *
    337      * @return string or null if the line is not in a function or method
    338      * @since  Method available since Release 1.2.0
    339      */
    340     public function getFunctionForLine($line)
    341     {
    342         $this->parse();
    343 
    344         if (isset($this->lineToFunctionMap[$line])) {
    345             return $this->lineToFunctionMap[$line];
    346         }
    347     }
    348 
    349     protected function parse()
    350     {
    351         $this->interfaces = array();
    352         $this->classes    = array();
    353         $this->traits     = array();
    354         $this->functions  = array();
    355         $class            = array();
    356         $classEndLine     = array();
    357         $trait            = false;
    358         $traitEndLine     = false;
    359         $interface        = false;
    360         $interfaceEndLine = false;
    361 
    362         foreach ($this->tokens as $token) {
    363             switch (get_class($token)) {
    364                 case 'PHP_Token_HALT_COMPILER':
    365                     return;
    366 
    367                 case 'PHP_Token_INTERFACE':
    368                     $interface        = $token->getName();
    369                     $interfaceEndLine = $token->getEndLine();
    370 
    371                     $this->interfaces[$interface] = array(
    372                       'methods'   => array(),
    373                       'parent'    => $token->getParent(),
    374                       'keywords'  => $token->getKeywords(),
    375                       'docblock'  => $token->getDocblock(),
    376                       'startLine' => $token->getLine(),
    377                       'endLine'   => $interfaceEndLine,
    378                       'package'   => $token->getPackage(),
    379                       'file'      => $this->filename
    380                     );
    381                     break;
    382 
    383                 case 'PHP_Token_CLASS':
    384                 case 'PHP_Token_TRAIT':
    385                     $tmp = array(
    386                       'methods'   => array(),
    387                       'parent'    => $token->getParent(),
    388                       'interfaces'=> $token->getInterfaces(),
    389                       'keywords'  => $token->getKeywords(),
    390                       'docblock'  => $token->getDocblock(),
    391                       'startLine' => $token->getLine(),
    392                       'endLine'   => $token->getEndLine(),
    393                       'package'   => $token->getPackage(),
    394                       'file'      => $this->filename
    395                     );
    396 
    397                     if ($token instanceof PHP_Token_CLASS) {
    398                         $class[]        = $token->getName();
    399                         $classEndLine[] = $token->getEndLine();
    400 
    401                         if ($class[count($class)-1] != 'anonymous class') {
    402                             $this->classes[$class[count($class)-1]] = $tmp;
    403                         }
    404                     } else {
    405                         $trait                = $token->getName();
    406                         $traitEndLine         = $token->getEndLine();
    407                         $this->traits[$trait] = $tmp;
    408                     }
    409                     break;
    410 
    411                 case 'PHP_Token_FUNCTION':
    412                     $name = $token->getName();
    413                     $tmp  = array(
    414                       'docblock'  => $token->getDocblock(),
    415                       'keywords'  => $token->getKeywords(),
    416                       'visibility'=> $token->getVisibility(),
    417                       'signature' => $token->getSignature(),
    418                       'startLine' => $token->getLine(),
    419                       'endLine'   => $token->getEndLine(),
    420                       'ccn'       => $token->getCCN(),
    421                       'file'      => $this->filename
    422                     );
    423 
    424                     if (empty($class) &&
    425                         $trait === false &&
    426                         $interface === false) {
    427                         $this->functions[$name] = $tmp;
    428 
    429                         $this->addFunctionToMap(
    430                             $name,
    431                             $tmp['startLine'],
    432                             $tmp['endLine']
    433                         );
    434                     } elseif (!empty($class) && $class[count($class)-1] != 'anonymous class') {
    435                         $this->classes[$class[count($class)-1]]['methods'][$name] = $tmp;
    436 
    437                         $this->addFunctionToMap(
    438                             $class[count($class)-1] . '::' . $name,
    439                             $tmp['startLine'],
    440                             $tmp['endLine']
    441                         );
    442                     } elseif ($trait !== false) {
    443                         $this->traits[$trait]['methods'][$name] = $tmp;
    444 
    445                         $this->addFunctionToMap(
    446                             $trait . '::' . $name,
    447                             $tmp['startLine'],
    448                             $tmp['endLine']
    449                         );
    450                     } else {
    451                         $this->interfaces[$interface]['methods'][$name] = $tmp;
    452                     }
    453                     break;
    454 
    455                 case 'PHP_Token_CLOSE_CURLY':
    456                     if (!empty($classEndLine) &&
    457                         $classEndLine[count($classEndLine)-1] == $token->getLine()) {
    458                         array_pop($classEndLine);
    459                         array_pop($class);
    460                     } elseif ($traitEndLine !== false &&
    461                         $traitEndLine == $token->getLine()) {
    462                         $trait        = false;
    463                         $traitEndLine = false;
    464                     } elseif ($interfaceEndLine !== false &&
    465                         $interfaceEndLine == $token->getLine()) {
    466                         $interface        = false;
    467                         $interfaceEndLine = false;
    468                     }
    469                     break;
    470             }
    471         }
    472     }
    473 
    474     /**
    475      * @return array
    476      */
    477     public function getLinesOfCode()
    478     {
    479         return $this->linesOfCode;
    480     }
    481 
    482     /**
    483      */
    484     public function rewind()
    485     {
    486         $this->position = 0;
    487     }
    488 
    489     /**
    490      * @return boolean
    491      */
    492     public function valid()
    493     {
    494         return isset($this->tokens[$this->position]);
    495     }
    496 
    497     /**
    498      * @return integer
    499      */
    500     public function key()
    501     {
    502         return $this->position;
    503     }
    504 
    505     /**
    506      * @return PHP_Token
    507      */
    508     public function current()
    509     {
    510         return $this->tokens[$this->position];
    511     }
    512 
    513     /**
    514      */
    515     public function next()
    516     {
    517         $this->position++;
    518     }
    519 
    520     /**
    521      * @param  integer $offset
    522      * @return boolean
    523      */
    524     public function offsetExists($offset)
    525     {
    526         return isset($this->tokens[$offset]);
    527     }
    528 
    529     /**
    530      * @param  integer $offset
    531      * @return mixed
    532      * @throws OutOfBoundsException
    533      */
    534     public function offsetGet($offset)
    535     {
    536         if (!$this->offsetExists($offset)) {
    537             throw new OutOfBoundsException(
    538                 sprintf(
    539                     'No token at position "%s"',
    540                     $offset
    541                 )
    542             );
    543         }
    544 
    545         return $this->tokens[$offset];
    546     }
    547 
    548     /**
    549      * @param integer $offset
    550      * @param mixed   $value
    551      */
    552     public function offsetSet($offset, $value)
    553     {
    554         $this->tokens[$offset] = $value;
    555     }
    556 
    557     /**
    558      * @param  integer $offset
    559      * @throws OutOfBoundsException
    560      */
    561     public function offsetUnset($offset)
    562     {
    563         if (!$this->offsetExists($offset)) {
    564             throw new OutOfBoundsException(
    565                 sprintf(
    566                     'No token at position "%s"',
    567                     $offset
    568                 )
    569             );
    570         }
    571 
    572         unset($this->tokens[$offset]);
    573     }
    574 
    575     /**
    576      * Seek to an absolute position.
    577      *
    578      * @param  integer $position
    579      * @throws OutOfBoundsException
    580      */
    581     public function seek($position)
    582     {
    583         $this->position = $position;
    584 
    585         if (!$this->valid()) {
    586             throw new OutOfBoundsException(
    587                 sprintf(
    588                     'No token at position "%s"',
    589                     $this->position
    590                 )
    591             );
    592         }
    593     }
    594 
    595     /**
    596      * @param string  $name
    597      * @param integer $startLine
    598      * @param integer $endLine
    599      */
    600     private function addFunctionToMap($name, $startLine, $endLine)
    601     {
    602         for ($line = $startLine; $line <= $endLine; $line++) {
    603             $this->lineToFunctionMap[$line] = $name;
    604         }
    605     }
    606 }