Last active
December 17, 2015 09:09
-
-
Save sasezaki/5585215 to your computer and use it in GitHub Desktop.
just a note
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * Zend Framework (http://framework.zend.com/) | |
| * | |
| * @link http://github.com/zendframework/zf2 for the canonical source repository | |
| * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) | |
| * @license http://framework.zend.com/license/new-bsd New BSD License | |
| */ | |
| namespace Zend\Code\Scanner; | |
| use Zend\Code\Annotation; | |
| use Zend\Code\Exception; | |
| use Zend\Code\NameInformation; | |
| class PropertyScanner implements ScannerInterface | |
| { | |
| /** | |
| * @var bool | |
| */ | |
| protected $isScanned = false; | |
| /** | |
| * @var array | |
| */ | |
| protected $tokens; | |
| /** | |
| * @var NameInformation | |
| */ | |
| protected $nameInformation; | |
| /** | |
| * @var string | |
| */ | |
| protected $class; | |
| /** | |
| * @var ClassScanner | |
| */ | |
| protected $scannerClass; | |
| /** | |
| * @var int | |
| */ | |
| protected $lineStart; | |
| /** | |
| * @var bool | |
| */ | |
| protected $isProtected = false; | |
| /** | |
| * @var bool | |
| */ | |
| protected $isPublic = true; | |
| /** | |
| * @var bool | |
| */ | |
| protected $isPrivate = false; | |
| /** | |
| * @var bool | |
| */ | |
| protected $isStatic = false; | |
| /** | |
| * @var string | |
| */ | |
| protected $docComment; | |
| /** | |
| * @var string | |
| */ | |
| protected $name; | |
| /** | |
| * @var string | |
| */ | |
| protected $value; | |
| /** | |
| * Constructor | |
| * | |
| * @param array $propertyTokens | |
| * @param NameInformation $nameInformation | |
| */ | |
| public function __construct(array $propertyTokens, NameInformation $nameInformation = null) | |
| { | |
| $this->tokens = $propertyTokens; | |
| $this->nameInformation = $nameInformation; | |
| } | |
| /** | |
| * @param string $class | |
| */ | |
| public function setClass($class) | |
| { | |
| $this->class = $class; | |
| } | |
| /** | |
| * @param ClassScanner $scannerClass | |
| */ | |
| public function setScannerClass(ClassScanner $scannerClass) | |
| { | |
| $this->scannerClass = $scannerClass; | |
| } | |
| /** | |
| * @return ClassScanner | |
| */ | |
| public function getClassScanner() | |
| { | |
| return $this->scannerClass; | |
| } | |
| /** | |
| * @return string | |
| */ | |
| public function getName() | |
| { | |
| $this->scan(); | |
| return $this->name; | |
| } | |
| /** | |
| * @return bool | |
| */ | |
| public function isPublic() | |
| { | |
| $this->scan(); | |
| return $this->isPublic; | |
| } | |
| /** | |
| * @return bool | |
| */ | |
| public function isPrivate() | |
| { | |
| $this->scan(); | |
| return $this->isPrivate; | |
| } | |
| /** | |
| * @return bool | |
| */ | |
| public function isProtected() | |
| { | |
| $this->scan(); | |
| return $this->isProtected; | |
| } | |
| /** | |
| * @return bool | |
| */ | |
| public function isStatic() | |
| { | |
| $this->scan(); | |
| return $this->isStatic; | |
| } | |
| /** | |
| * @return string | |
| */ | |
| public function getValue() | |
| { | |
| $this->scan(); | |
| return $this->value; | |
| } | |
| /** | |
| * @return string | |
| */ | |
| public function getDocComment() | |
| { | |
| $this->scan(); | |
| return $this->docComment; | |
| } | |
| /** | |
| * @param Annotation\AnnotationManager $annotationManager | |
| * @return AnnotationScanner | |
| */ | |
| public function getAnnotations(Annotation\AnnotationManager $annotationManager) | |
| { | |
| if (($docComment = $this->getDocComment()) == '') { | |
| return false; | |
| } | |
| return new AnnotationScanner($annotationManager, $docComment, $this->nameInformation); | |
| } | |
| /** | |
| * @return string | |
| */ | |
| public function __toString() | |
| { | |
| $this->scan(); | |
| return var_export($this, true); | |
| } | |
| /** | |
| * Scan tokens | |
| * | |
| * @throws \Zend\Code\Exception\RuntimeException | |
| */ | |
| protected function scan() | |
| { | |
| if ($this->isScanned) { | |
| return; | |
| } | |
| if (!$this->tokens) { | |
| throw new Exception\RuntimeException('No tokens were provided'); | |
| } | |
| /** | |
| * Variables & Setup | |
| */ | |
| $tokens = &$this->tokens; | |
| reset($tokens); | |
| $tokenValueLoop = false; | |
| $scanValueStart = false; | |
| SCANNER_TOP: | |
| $token = current($tokens); | |
| if (!is_string($token)) { | |
| list($tokenType, $tokenContent, $tokenLine) = $token; | |
| switch ($tokenType) { | |
| case T_DOC_COMMENT: | |
| if ($this->docComment === null && $this->name === null) { | |
| $this->docComment = $tokenContent; | |
| } | |
| $tokenValueLoop = false; | |
| goto SCANNER_CONTINUE; | |
| case T_VARIABLE: | |
| $this->name = ltrim($tokenContent, '$'); | |
| $tokenValueLoop = false; | |
| goto SCANNER_CONTINUE; | |
| case T_PUBLIC: | |
| // use defaults | |
| $tokenValueLoop = false; | |
| goto SCANNER_CONTINUE; | |
| case T_PROTECTED: | |
| $this->isProtected = true; | |
| $this->isPublic = false; | |
| $tokenValueLoop = false; | |
| goto SCANNER_CONTINUE; | |
| case T_PRIVATE: | |
| $this->isPrivate = true; | |
| $this->isPublic = false; | |
| $tokenValueLoop = false; | |
| goto SCANNER_CONTINUE; | |
| case T_STATIC: | |
| $this->isStatic = true; | |
| $tokenValueLoop = false; | |
| goto SCANNER_CONTINUE; | |
| default: | |
| if ($scanValueStart === false && $tokenType === T_WHITESPACE) { | |
| goto SCANNER_CONTINUE; | |
| } | |
| $scanValueStart = true; | |
| if ($tokenValueLoop === false) { | |
| $propertyValue = new PropertyValue; | |
| } | |
| $propertyValue->add($token); | |
| // old | |
| if ($this->name !== null && trim($tokenContent) !== '') { | |
| //var_dump(__METHOD__, $token, token_name($token[0]), $tokenContent, $tokenLine); | |
| $this->value .= (is_string($token)) ? $token : $tokenContent; | |
| if (substr($this->value, 0, 1) === '"' || substr($this->value, 0, 1) === "'") { | |
| $this->value = substr($this->value, 1, -1); // Remove quotes | |
| } | |
| } | |
| $tokenValueLoop = true; | |
| goto SCANNER_CONTINUE; | |
| } | |
| } else { | |
| if (isset($propertyValue)) { | |
| if ($token !== ';') { | |
| $propertyValue->add($token); | |
| } | |
| } | |
| } | |
| SCANNER_CONTINUE: | |
| if (next($this->tokens) === false) { | |
| if (isset($propertyValue)) { | |
| //var_dump($propertyValue); | |
| //$propertyValue->scan(); | |
| $propertyValue->debug(); | |
| }; | |
| goto SCANNER_END; | |
| } | |
| goto SCANNER_TOP; | |
| SCANNER_END: | |
| $this->isScanned = true; | |
| } | |
| } | |
| class PropertyValueArray implements \Iterator | |
| { | |
| private $position = 0; | |
| private $tokenPosition = 0; | |
| private $numerical_count = 0; | |
| private $tokens; | |
| private $current; | |
| public function __construct($tokens) | |
| { | |
| var_dump($tokens); | |
| $this->tokens = $tokens; | |
| } | |
| public function current() | |
| { | |
| return $this->current; | |
| } | |
| public function next() | |
| { | |
| ++$this->position; | |
| ++$this->tokenPosition; | |
| $this->fetch(); | |
| } | |
| protected function fetch() | |
| { | |
| do { | |
| if (!isset($this->tokens[$this->tokenPosition])) { | |
| break; | |
| } | |
| if (is_array($this->tokens[$this->tokenPosition])) { | |
| if ($this->tokens[$this->tokenPosition][0] === T_WHITESPACE) { | |
| ++$this->tokenPosition; | |
| continue; | |
| } | |
| if ($this->tokens[$this->tokenPosition][1] === '=>') { | |
| ++$this->tokenPosition; | |
| continue; | |
| } | |
| if ($this->tokens[$this->tokenPosition][1] === 'array') { | |
| if ($this->tokenPosition == 0) { | |
| ++$this->tokenPosition; | |
| continue; | |
| } else { | |
| // multidimentional | |
| $multi_start = $this->tokenPosition; | |
| do { | |
| if ($this->tokens[$this->tokenPosition] === ')') { | |
| $tokens = $this->tokens; | |
| $tokens = array_slice($tokens, $multi_start, $this->tokenPosition + 1 - $multi_start); | |
| ++$this->tokenPosition; | |
| break; | |
| } | |
| ++$this->tokenPosition; | |
| } while (true); | |
| $this->current = new self($tokens); | |
| } | |
| } | |
| // is key or value ? | |
| if (isset($this->tokens[$this->tokenPosition + 1])) { | |
| if ( | |
| $this->tokens[$this->tokenPosition + 1] === ',' || | |
| $this->tokens[$this->tokenPosition + 1] === ')' | |
| ) { | |
| $value = $this->tokens[$this->tokenPosition][1]; | |
| break; | |
| } | |
| if ( | |
| ( | |
| is_array($this->tokens[$this->tokenPosition + 1]) && | |
| $this->tokens[$this->tokenPosition + 1][0] === T_WHITESPACE) | |
| && | |
| ( | |
| $this->tokens[$this->tokenPosition + 2] === ',' || | |
| $this->tokens[$this->tokenPosition + 2] === ')' | |
| ) | |
| ) { | |
| $value = $this->tokens[$this->tokenPosition][1]; | |
| break; | |
| } | |
| } | |
| if (is_array($this->tokens[$this->tokenPosition])) { | |
| $key = $this->tokens[$this->tokenPosition][1]; | |
| } else { | |
| goto FETCH_END; | |
| } | |
| } | |
| ++$this->tokenPosition; | |
| } while (true); | |
| if (!isset($value)) { | |
| goto FETCH_END; | |
| } | |
| $this->current = array('key' => (isset($key))? $key : $this->numerical_count, 'value' => $value); | |
| if (!isset($key)) ++$this->numerical_count; | |
| FETCH_END: | |
| } | |
| public function key() | |
| { | |
| return $this->position; | |
| } | |
| public function valid() | |
| { | |
| return $this->tokenPosition < count($this->tokens); | |
| } | |
| public function rewind() | |
| { | |
| $this->position = 0; | |
| $this->tokenPosition = 0; | |
| $this->fetch(); | |
| } | |
| public function scan(){ | |
| $count_current_tokens = count($this->tokens); | |
| $array_token = array(); | |
| $left_count = 0; // ( | |
| for ($i = 0; $i < $count_current_tokens; $i++) { | |
| if ($this->tokens[$i] === '(') { | |
| $left_count++; | |
| } | |
| if ($this->tokens[$i] === ')') { | |
| $left_count--; | |
| } | |
| if (is_array($this->tokens[$i])) { | |
| $array_token; | |
| } | |
| } | |
| } | |
| } | |
| class PropertyValue | |
| { | |
| private $scanned; | |
| private $tokens = array(); | |
| private $value; | |
| public function add($token) | |
| { | |
| $this->tokens[] = $token; | |
| } | |
| public function debug(){ | |
| //var_dump(count($this->tokens)); | |
| //var_dump($this->tokens[0][1]); | |
| if (count($this->tokens) === 1) { //just a string or boolean or CONST | |
| $serializer = new \Zend\Serializer\Adapter\PhpCode; | |
| var_dump($serializer->unserialize($this->tokens[0][1])); | |
| } else { | |
| $propertyValueArray = new PropertyValueArray($this->tokens); | |
| foreach ($propertyValueArray as $a) { | |
| var_dump($a); | |
| } | |
| /** | |
| $propertyValueArray->rewind(); | |
| //var_dump($propertyValueArray); | |
| var_dump($propertyValueArray->current()); | |
| $propertyValueArray->next(); | |
| var_dump($propertyValueArray->current()); | |
| $propertyValueArray->next(); | |
| var_dump($propertyValueArray->current());*/ | |
| } | |
| } | |
| public function getTokens() | |
| { | |
| return $this->tokens; | |
| } | |
| public function getValue() | |
| { | |
| $this->scan(); | |
| return $this->value; | |
| } | |
| public function scan() | |
| { | |
| if ($this->scanned) { | |
| return; //already scanned; | |
| } | |
| $tokens = $this->tokens; | |
| return; | |
| foreach ($tokens as $token) { | |
| //if (in_array($token[0], array(T_WHITESPACE))) { //ignore | |
| // continue; | |
| //} | |
| if ($token[0] === T_ARRAY) { | |
| $value = new PropertyValue($token); | |
| $value->scan(); | |
| $this->value[] = $value->getValue(); | |
| } else { | |
| $this->value[] = $token; | |
| } | |
| } | |
| return; | |
| $token_start = current($tokens); | |
| if ($token_start[0] === T_ARRAY) { | |
| array_shift($tokens); | |
| $this->tokens = $tokens; | |
| $this->scan(); | |
| /** | |
| array_shift($tokens); | |
| $value = new PropertyValue(); | |
| foreach ($tokens as $token) { | |
| if ($token[0] === T_ARRAY) { | |
| } | |
| $value->add($token); | |
| } | |
| $this->value = $value; | |
| return; | |
| */ | |
| } | |
| if (!$this->value) { | |
| $this->value = new PropertyValue(); | |
| } | |
| $this->value->add($tokens); | |
| $this->scanned = true; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| use Zend\Code\Scanner; | |
| spl_autoload_register(function($class){ | |
| if ($class === 'Zend\Code\Scanner\PropertyScanner') { | |
| include __DIR__.'/PropertyScanner_patch.php'; | |
| } | |
| }); | |
| require dirname( __DIR__).'/tests/_autoload.php'; | |
| $code = <<<'CODE' | |
| <?php | |
| class Abc | |
| { | |
| protected $boolean = false; | |
| protected $fo = array('a' => 1, 'b', 'c' => 3); | |
| protected $foo = array('x' => 9 ,array(3,6), 2); | |
| protected $string = 'xx'; | |
| protected $bar2, $bar3; | |
| } | |
| CODE; | |
| ////syntax check | |
| eval(substr($code, 5)); | |
| $property = (isset($argv[1])) ? $argv[1] : 'foo'; | |
| $scanner = new Scanner\TokenArrayScanner(token_get_all($code)); | |
| var_dump($scanner->getClass('Abc')->getProperty($property)->getValue()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment