Viewing file: Stream.php (15.41 KB) -rw-rw-rw- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php /** * php-token-stream * * Copyright (c) 2009-2012, Sebastian Bergmann <sb@sebastian-bergmann.de>. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of Sebastian Bergmann nor the names of his * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * @package PHP_TokenStream * @author Sebastian Bergmann <sb@sebastian-bergmann.de> * @copyright 2009-2012 Sebastian Bergmann <sb@sebastian-bergmann.de> * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License * @since File available since Release 1.0.0 */
/** * A stream of PHP tokens. * * @author Sebastian Bergmann <sb@sebastian-bergmann.de> * @copyright 2009-2012 Sebastian Bergmann <sb@sebastian-bergmann.de> * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License * @version Release: 1.1.5 * @link http://github.com/sebastianbergmann/php-token-stream/tree * @since Class available since Release 1.0.0 */ class PHP_Token_Stream implements ArrayAccess, Countable, SeekableIterator { /** * @var array */ protected static $customTokens = array( '(' => 'PHP_Token_OPEN_BRACKET', ')' => 'PHP_Token_CLOSE_BRACKET', '[' => 'PHP_Token_OPEN_SQUARE', ']' => 'PHP_Token_CLOSE_SQUARE', '{' => 'PHP_Token_OPEN_CURLY', '}' => 'PHP_Token_CLOSE_CURLY', ';' => 'PHP_Token_SEMICOLON', '.' => 'PHP_Token_DOT', ',' => 'PHP_Token_COMMA', '=' => 'PHP_Token_EQUAL', '<' => 'PHP_Token_LT', '>' => 'PHP_Token_GT', '+' => 'PHP_Token_PLUS', '-' => 'PHP_Token_MINUS', '*' => 'PHP_Token_MULT', '/' => 'PHP_Token_DIV', '?' => 'PHP_Token_QUESTION_MARK', '!' => 'PHP_Token_EXCLAMATION_MARK', ':' => 'PHP_Token_COLON', '"' => 'PHP_Token_DOUBLE_QUOTES', '@' => 'PHP_Token_AT', '&' => 'PHP_Token_AMPERSAND', '%' => 'PHP_Token_PERCENT', '|' => 'PHP_Token_PIPE', '$' => 'PHP_Token_DOLLAR', '^' => 'PHP_Token_CARET', '~' => 'PHP_Token_TILDE', '`' => 'PHP_Token_BACKTICK' );
/** * @var string */ protected $filename;
/** * @var array */ protected $tokens = array();
/** * @var integer */ protected $position = 0;
/** * @var array */ protected $linesOfCode = array('loc' => 0, 'cloc' => 0, 'ncloc' => 0);
/** * @var array */ protected $classes;
/** * @var array */ protected $functions;
/** * @var array */ protected $includes;
/** * @var array */ protected $interfaces;
/** * @var array */ protected $traits;
/** * Constructor. * * @param string $sourceCode */ public function __construct($sourceCode) { if (is_file($sourceCode)) { $this->filename = $sourceCode; $sourceCode = file_get_contents($sourceCode); }
$this->scan($sourceCode); }
/** * Destructor. */ public function __destruct() { $this->tokens = array(); }
/** * @return string */ public function __toString() { $buffer = '';
foreach ($this as $token) { $buffer .= $token; }
return $buffer; }
/** * @return string * @since Method available since Release 1.1.0 */ public function getFilename() { return $this->filename; }
/** * Scans the source for sequences of characters and converts them into a * stream of tokens. * * @param string $sourceCode */ protected function scan($sourceCode) { $line = 1; $tokens = token_get_all($sourceCode); $numTokens = count($tokens);
for ($i = 0; $i < $numTokens; ++$i) { $token = $tokens[$i]; unset($tokens[$i]);
if (is_array($token)) { $text = $token[1]; $tokenClass = 'PHP_Token_' . substr(token_name($token[0]), 2); } else { $text = $token; $tokenClass = self::$customTokens[$token]; }
$this->tokens[] = new $tokenClass($text, $line, $this, $i); $lines = substr_count($text, "\n"); $line += $lines;
if ($tokenClass == 'PHP_Token_HALT_COMPILER') { break; }
else if ($tokenClass == 'PHP_Token_COMMENT' || $tokenClass == 'PHP_Token_DOC_COMMENT') { $this->linesOfCode['cloc'] += $lines + 1; } }
$this->linesOfCode['loc'] = substr_count($sourceCode, "\n"); $this->linesOfCode['ncloc'] = $this->linesOfCode['loc'] - $this->linesOfCode['cloc']; }
/** * @return integer */ public function count() { return count($this->tokens); }
/** * @return PHP_Token[] */ public function tokens() { return $this->tokens; }
/** * @return array */ public function getClasses() { if ($this->classes !== NULL) { return $this->classes; }
$this->parse();
return $this->classes; }
/** * @return array */ public function getFunctions() { if ($this->functions !== NULL) { return $this->functions; }
$this->parse();
return $this->functions; }
/** * @return array */ public function getInterfaces() { if ($this->interfaces !== NULL) { return $this->interfaces; }
$this->parse();
return $this->interfaces; }
/** * @return array * @since Method available since Release 1.1.0 */ public function getTraits() { if ($this->traits !== NULL) { return $this->traits; }
$this->parse();
return $this->traits; }
/** * Gets the names of all files that have been included * using include(), include_once(), require() or require_once(). * * Parameter $categorize set to TRUE causing this function to return a * multi-dimensional array with categories in the keys of the first dimension * and constants and their values in the second dimension. * * Parameter $category allow to filter following specific inclusion type * * @param bool $categorize OPTIONAL * @param string $category OPTIONAL Either 'require_once', 'require', * 'include_once', 'include'. * @return array * @since Method available since Release 1.1.0 */ public function getIncludes($categorize = FALSE, $category = NULL) { if ($this->includes === NULL) { $this->includes = array( 'require_once' => array(), 'require' => array(), 'include_once' => array(), 'include' => array() );
foreach ($this->tokens as $token) { switch (get_class($token)) { case 'PHP_Token_REQUIRE_ONCE': case 'PHP_Token_REQUIRE': case 'PHP_Token_INCLUDE_ONCE': case 'PHP_Token_INCLUDE': { $this->includes[$token->getType()][] = $token->getName(); } break; } } }
if (isset($this->includes[$category])) { $includes = $this->includes[$category]; }
else if ($categorize === FALSE) { $includes = array_merge( $this->includes['require_once'], $this->includes['require'], $this->includes['include_once'], $this->includes['include'] ); } else { $includes = $this->includes; }
return $includes; }
protected function parse() { $this->interfaces = array(); $this->classes = array(); $this->traits = array(); $this->functions = array(); $class = FALSE; $classEndLine = FALSE; $trait = FALSE; $traitEndLine = FALSE; $interface = FALSE; $interfaceEndLine = FALSE;
foreach ($this->tokens as $token) { switch (get_class($token)) { case 'PHP_Token_HALT_COMPILER': { return; } break;
case 'PHP_Token_INTERFACE': { $interface = $token->getName(); $interfaceEndLine = $token->getEndLine();
$this->interfaces[$interface] = array( 'methods' => array(), 'parent' => $token->getParent(), 'keywords' => $token->getKeywords(), 'docblock' => $token->getDocblock(), 'startLine' => $token->getLine(), 'endLine' => $interfaceEndLine, 'package' => $token->getPackage(), 'file' => $this->filename ); } break;
case 'PHP_Token_CLASS': case 'PHP_Token_TRAIT': { $tmp = array( 'methods' => array(), 'parent' => $token->getParent(), 'interfaces'=> $token->getInterfaces(), 'keywords' => $token->getKeywords(), 'docblock' => $token->getDocblock(), 'startLine' => $token->getLine(), 'endLine' => $token->getEndLine(), 'package' => $token->getPackage(), 'file' => $this->filename );
if ($token instanceof PHP_Token_CLASS) { $class = $token->getName(); $classEndLine = $token->getEndLine(); $this->classes[$class] = $tmp; } else { $trait = $token->getName(); $traitEndLine = $token->getEndLine(); $this->traits[$trait] = $tmp; } } break;
case 'PHP_Token_FUNCTION': { $name = $token->getName(); $tmp = array( 'docblock' => $token->getDocblock(), 'keywords' => $token->getKeywords(), 'visibility'=> $token->getVisibility(), 'signature' => $token->getSignature(), 'startLine' => $token->getLine(), 'endLine' => $token->getEndLine(), 'ccn' => $token->getCCN(), 'file' => $this->filename );
if ($class === FALSE && $trait === FALSE && $interface === FALSE) { $this->functions[$name] = $tmp; }
else if ($class !== FALSE) { $this->classes[$class]['methods'][$name] = $tmp; }
else if ($trait !== FALSE) { $this->traits[$trait]['methods'][$name] = $tmp; }
else { $this->interfaces[$interface]['methods'][$name] = $tmp; } } break;
case 'PHP_Token_CLOSE_CURLY': { if ($classEndLine !== FALSE && $classEndLine == $token->getLine()) { $class = FALSE; $classEndLine = FALSE; }
else if ($traitEndLine !== FALSE && $traitEndLine == $token->getLine()) { $trait = FALSE; $traitEndLine = FALSE; }
else if ($interfaceEndLine !== FALSE && $interfaceEndLine == $token->getLine()) { $interface = FALSE; $interfaceEndLine = FALSE; } } break; } } }
/** * @return array */ public function getLinesOfCode() { return $this->linesOfCode; }
/** */ public function rewind() { $this->position = 0; }
/** * @return boolean */ public function valid() { return isset($this->tokens[$this->position]); }
/** * @return integer */ public function key() { return $this->position; }
/** * @return PHP_Token */ public function current() { return $this->tokens[$this->position]; }
/** */ public function next() { $this->position++; }
/** * @param mixed $offset */ public function offsetExists($offset) { return isset($this->tokens[$offset]); }
/** * @param mixed $offset * @return mixed */ public function offsetGet($offset) { return $this->tokens[$offset]; }
/** * @param mixed $offset * @param mixed $value */ public function offsetSet($offset, $value) { $this->tokens[$offset] = $value; }
/** * @param mixed $offset */ public function offsetUnset($offset) { unset($this->tokens[$offset]); }
/** * Seek to an absolute position. * * @param integer $position * @throws OutOfBoundsException */ public function seek($position) { $this->position = $position;
if (!$this->valid()) { throw new OutOfBoundsException('Invalid seek position'); } } }
|