pax_global_header00006660000000000000000000000064123704546640014525gustar00rootroot0000000000000052 comment=e6d0ac2baf66cdf154be34c3d2a2aa1bd4b426ee PHP-Token-Reflection-1.4.0/000077500000000000000000000000001237045466400153245ustar00rootroot00000000000000PHP-Token-Reflection-1.4.0/LICENSE.md000066400000000000000000000027351237045466400167370ustar00rootroot00000000000000# PHP Token Reflection # Copyright (c) 2011-2012, Ondřej Nešpor, Jaroslav Hanslík. 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. * The names of authors and contributors may not 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. PHP-Token-Reflection-1.4.0/README.md000066400000000000000000000176771237045466400166250ustar00rootroot00000000000000# PHP Token Reflection # [![Build Status](https://secure.travis-ci.org/Andrewsville/PHP-Token-Reflection.png?branch=develop)](http://travis-ci.org/Andrewsville/PHP-Token-Reflection) In short, this library emulates the PHP reflection model using the tokenized PHP source. The basic concept is, that any reflection is possible to process the particular part of the token array describing the reflected element. It is also able to find out if there are any child elements (a class reflection is able to find method definitions in the source, for example), create their reflections and pass the appropriate part of the token array to them. This concept allows us to keep the parser code relatively simple and easily maintainable. And we are able to to create all reflections in a single pass. That is absolutely crucial for the performance of the library. All reflection instances are being kept in a [TokenReflection\\Broker](https://github.com/Andrewsville/PHP-Token-Reflection/blob/master/library/TokenReflection/Broker.php) instance and all reflections know the broker that created them. This is very important, because a class reflection, for example, holds all its constants, methods and properties reflections instantiated inside, however it knows absolutely nothing about its parent class or the interfaces it implements. It knows just their fully qualified names. So when you call ```$reflectionClass->getParentClass();```, the class reflection asks the Broker for a reflection of a class by its name and returns it. An interesting thing happens when there is a parent class defined but it was not processed (in other words, you ask the Broker for a class that it does not know). It still returns a reflection! Yes, we do have reflections for classes that do not exist! COOL! There are reflections for file (\*), file-namespace (\*), namespace, class, function/method, constant, property and parameter. You will not normally get in touch with those marked with an asterisk but they are used internally. **ReflectionFile** is the topmost structure in our reflection tree. It gets the whole tokenized source and tries to find namespaces there. If it does, it creates ReflectionFileNamespace instances and passes them the appropriate part of the tokens array. If not, it creates a single pseudo-namespace (called no-namespace) a passes the whole tokenized source to it. **ReflectionFileNamespace** gets the namespace definition from the file, finds out its name, other aliased namespaces and tries to find any defined constants, functions and classes. If it finds any, it creates their reflections and passes them the appropriate parts of the tokens array. **ReflectionNamespace** is a similar (in name) yet quite different (in meaning) structure. It is a unique structure for every namespace and it holds all constants, functions and classes from this particular namespace inside. In fact, it is a simple container. It also is not created directly by any parent reflection, but the Broker creates it. Why do we need two separate classes? Because namespaces can be split into many files and in each file it can have individual namespace aliases. And those have to be taken into consideration when resolving parent class/interface names. It means that a ReflectionFileNamespace is created for every namespace in every file and it parses its contents, resolves fully qualified names of all classes, their parents and interfaces. Later, the Broker takes all ReflectionFileNamespace instances of the same namespace and merges them into a single ReflectionNameaspace instance. **ReflectionClass**, **ReflectionFunction**, **ReflectionMethod**, **ReflectionParameter** and **ReflectionProperty** work the same way like their internal reflection namesakes. **ReflectionConstants** is our addition to the reflection model. There is not much it can do - it can return its name, value (we will speak about values later) and how it was defined. (Almost) all reflection classes share a common base class, that defines some common functionality and interface. This means that our reflection model is much more unified than the internal one. There are reflections for the tokenized source (those mentioned above), but also descendants of the internal reflection that implement our additional features (they both use the same interface). They represent the PHP's internal classes, functions, ... So when you ask the Broker for an internal class, it returns a [TokenReflection\\Php\\ReflectionClass](https://github.com/Andrewsville/PHP-Token-Reflection/blob/master/library/TokenReflection/Php/ReflectionClass.php) instance that encapsulates the internal reflection functionality and adds our features. And there is also the [TokenReflection\\Php\\ReflectionConstant](https://github.com/Andrewsville/PHP-Token-Reflection/blob/master/library/TokenReflection/Php/ReflectionConstant.php) class that has no parent in the internal reflection model. ## Remarks From the beginning we tried to be as compatible as possible with the internal reflection (including things like returning the interface list in the same - pretty weird - order). However there are situations where it is just impossible (for example we prefer consistency over compatibility with the internal reflection and will not introduce [this bug](https://bugs.php.net/bug.php?id=62715) into the library :). We are limited in the way we can handle constant values and property and parameter default values. When defined as a constant, we do our best to resolve its value (within parsed and internal constants) and use it. This is eventually made via a combination of ```var_export()``` and ```eval()```. Yes, that sucks, but there is no better way. Moreover the referenced constant may not exist. In that case it is replaced by a ```~~NOT RESOLVED~~``` string. Runtime constants are not supported. When the library encounters a duplicate class, function or constant name, it converts the previously created reflection into an "invalid reflection" instance. That means that the parser is unable to distinguish between such classes and it is unable to build a proper class tree for example. And it throws an exception. When you catch this exception and continue to work with the Broker instance, the duplicate classes, functions or constants will have only one reflection and it will be an instance of **Invalid\ReflectionClass**, **Invalid\ReflectionFunction** or **Invalid\ReflectionConstant** respectively. ## Usage To be able to work with reflections you have to let the library parse the source code first. That is what [TokenReflection\\Broker](https://github.com/Andrewsville/PHP-Token-Reflection/blob/master/library/TokenReflection/Broker.php) does. It walks through the given directories, tokenizes PHP sources and caches reflection objects. Moreover, you cannot just instantiate a reflection class. You have to ask the Broker for the reflection. And once you have a reflection instance, everything works as expected :) ```php processDirectory('~/lib/Zend_Framework'); $class = $broker->getClass('Zend_Version'); // returns a TokenReflection\ReflectionClass instance $class = $broker->getClass('Exception'); // returns a TokenReflection\Php\ReflectionClass instance $class = $broker->getClass('Nonexistent'); // returns a TokenReflection\Dummy\ReflectionClass instance $function = $broker->getFunction(...); $constant = $broker->getConstant(...); ``` ## Requirements The library requires PHP 5.3 with the [tokenizer extension](http://cz.php.net/manual/en/book.tokenizer.php) enabled. If you want to process PHAR archives, you will require the [appropriate extension](http://cz.php.net/manual/en/book.phar.php) enabled as well. ## Current status The current version should support the vast majority of PHP internal reflection features and add many more. Every release is tested using our testing package (several PHP frameworks and other libraries) and its compatibility is tested on all PHP versions of the 5.3 and 5.4 branch and the actual trunk. PHP-Token-Reflection-1.4.0/TokenReflection/000077500000000000000000000000001237045466400204175ustar00rootroot00000000000000PHP-Token-Reflection-1.4.0/TokenReflection/Broker.php000066400000000000000000000341351237045466400223620ustar00rootroot00000000000000cache = array( self::CACHE_NAMESPACE => array(), self::CACHE_CLASS => array(), self::CACHE_CONSTANT => array(), self::CACHE_FUNCTION => array() ); $this->options = $options; $this->backend = $backend ->setBroker($this) ->setStoringTokenStreams((bool) ($options & self::OPTION_SAVE_TOKEN_STREAM)); } /** * Returns broker/parser options. * * @return integer */ public function getOptions() { return $this->options; } /** * Returns if a particular option setting is set. * * @param integer $option Option setting * @return boolean */ public function isOptionSet($option) { return (bool) ($this->options & $option); } /** * Parses a string with the PHP source code using the given file name and returns the appropriate reflection object. * * @param string $source PHP source code * @param string $fileName Used file name * @param boolean $returnReflectionFile Returns the appropriate \TokenReflection\ReflectionFile instance(s) * @return boolean|\TokenReflection\ReflectionFile */ public function processString($source, $fileName, $returnReflectionFile = false) { if ($this->backend->isFileProcessed($fileName)) { $tokens = $this->backend->getFileTokens($fileName); } else { $tokens = new Stream\StringStream($source, $fileName); } $reflectionFile = new ReflectionFile($tokens, $this); if (!$this->backend->isFileProcessed($fileName)) { $this->backend->addFile($tokens, $reflectionFile); // Clear the cache - leave only tokenized reflections foreach ($this->cache as $type => $cached) { if (!empty($cached)) { $this->cache[$type] = array_filter($cached, function(IReflection $reflection) { return $reflection->isTokenized(); }); } } } return $returnReflectionFile ? $reflectionFile : true; } /** * Parses a file and returns the appropriate reflection object. * * @param string $fileName Filename * @param boolean $returnReflectionFile Returns the appropriate \TokenReflection\ReflectionFile instance(s) * @return boolean|\TokenReflection\ReflectionFile * @throws \TokenReflection\Exception\BrokerException If the file could not be processed. */ public function processFile($fileName, $returnReflectionFile = false) { try { if ($this->backend->isFileProcessed($fileName)) { $tokens = $this->backend->getFileTokens($fileName); } else { $tokens = new Stream\FileStream($fileName); } $reflectionFile = new ReflectionFile($tokens, $this); if (!$this->backend->isFileProcessed($fileName)) { $this->backend->addFile($tokens, $reflectionFile); // Clear the cache - leave only tokenized reflections foreach ($this->cache as $type => $cached) { if (!empty($cached)) { $this->cache[$type] = array_filter($cached, function(IReflection $reflection) { return $reflection->isTokenized(); }); } } } return $returnReflectionFile ? $reflectionFile : true; } catch (Exception\ParseException $e) { throw $e; } catch (Exception\StreamException $e) { throw new Exception\BrokerException($this, 'Could not process the file.', 0, $e); } } /** * Processes a PHAR archive. * * @param string $fileName Archive filename. * @param boolean $returnReflectionFile Returns the appropriate \TokenReflection\ReflectionFile instance(s) * @return boolean|array of \TokenReflection\ReflectionFile * @throws \TokenReflection\Exception\BrokerException If the PHAR PHP extension is not loaded. * @throws \TokenReflection\Exception\BrokerException If the given archive could not be read. * @throws \TokenReflection\Exception\BrokerException If the given archive could not be processed. */ public function processPhar($fileName, $returnReflectionFile = false) { if (!is_file($fileName)) { throw new Exception\BrokerException($this, 'File does not exist.', Exception\BrokerException::DOES_NOT_EXIST); } if (!extension_loaded('Phar')) { throw new Exception\BrokerException($this, 'The PHAR PHP extension is not loaded.', Exception\BrokerException::PHP_EXT_MISSING); } try { $result = array(); foreach (new RecursiveIteratorIterator(new \Phar($fileName)) as $entry) { if ($entry->isFile()) { $result[$entry->getPathName()] = $this->processFile($entry->getPathName(), $returnReflectionFile); } } return $returnReflectionFile ? $result : true; } catch (Exception\ParseException $e) { throw $e; } catch (Exception\StreamException $e) { throw new Exception\BrokerException($this, 'Could not process the archive.', 0, $e); } } /** * Processes recursively a directory and returns an array of file reflection objects. * * @param string $path Directora path * @param string|array $filters Filename filters * @param boolean $returnReflectionFile Returns the appropriate \TokenReflection\ReflectionFile instance(s) * @return boolean|array of \TokenReflection\ReflectionFile * @throws \TokenReflection\Exception\BrokerException If the given directory does not exist. * @throws \TokenReflection\Exception\BrokerException If the given directory could not be processed. */ public function processDirectory($path, $filters = array(), $returnReflectionFile = false) { $realPath = realpath($path); if (!is_dir($realPath)) { throw new Exception\BrokerException($this, 'File does not exist.', Exception\BrokerException::DOES_NOT_EXIST); } try { $result = array(); foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($realPath)) as $entry) { if ($entry->isFile()) { $process = empty($filters); if (!$process) { foreach ((array) $filters as $filter) { $whitelisting = '!' !== $filter{0}; if (fnmatch($whitelisting ? $filter : substr($filter, 1), $entry->getPathName(), FNM_NOESCAPE)) { $process = $whitelisting; } } } if ($process) { $result[$entry->getPathName()] = $this->processFile($entry->getPathName(), $returnReflectionFile); } } } return $returnReflectionFile ? $result : true; } catch (Exception\ParseException $e) { throw $e; } catch (Exception\StreamException $e) { throw new Exception\BrokerException($this, 'Could not process the directory.', 0, $e); } } /** * Process a file, directory or a PHAR archive. * * @param string $path Path * @param boolean $returnReflectionFile Returns the appropriate \TokenReflection\ReflectionFile instance(s) * @return boolean|array|\TokenReflection\ReflectionFile * @throws \TokenReflection\Exception\BrokerException If the target does not exist. */ public function process($path, $returnReflectionFile = false) { if (is_dir($path)) { return $this->processDirectory($path, array(), $returnReflectionFile); } elseif (is_file($path)) { if (preg_match('~\\.phar(?:$|\\.)~i', $path)) { return $this->processPhar($path, $returnReflectionFile); } return $this->processFile($path, $returnReflectionFile); } else { throw new Exception\BrokerException($this, 'The given directory/file does not exist.', Exception\BrokerException::DOES_NOT_EXIST); } } /** * Returns if the broker contains a namespace of the given name. * * @param string $namespaceName Namespace name * @return boolean */ public function hasNamespace($namespaceName) { return isset($this->cache[self::CACHE_NAMESPACE][$namespaceName]) || $this->backend->hasNamespace($namespaceName); } /** * Returns a reflection object of the given namespace. * * @param string $namespaceName Namespace name * @return \TokenReflection\ReflectionNamespace|null */ public function getNamespace($namespaceName) { $namespaceName = ltrim($namespaceName, '\\'); if (isset($this->cache[self::CACHE_NAMESPACE][$namespaceName])) { return $this->cache[self::CACHE_NAMESPACE][$namespaceName]; } $namespace = $this->backend->getNamespace($namespaceName); if (null !== $namespace) { $this->cache[self::CACHE_NAMESPACE][$namespaceName] = $namespace; } return $namespace; } /** * Returns if the broker contains a class of the given name. * * @param string $className Class name * @return boolean */ public function hasClass($className) { return isset($this->cache[self::CACHE_CLASS][$className]) || $this->backend->hasClass($className); } /** * Returns a reflection object of the given class (FQN expected). * * @param string $className CLass bame * @return \TokenReflection\ReflectionClass|null */ public function getClass($className) { $className = ltrim($className, '\\'); if (isset($this->cache[self::CACHE_CLASS][$className])) { return $this->cache[self::CACHE_CLASS][$className]; } $this->cache[self::CACHE_CLASS][$className] = $this->backend->getClass($className); return $this->cache[self::CACHE_CLASS][$className]; } /** * Returns all classes from all namespaces. * * @param integer $types Returned class types (multiple values may be OR-ed) * @return array */ public function getClasses($types = Broker\Backend::TOKENIZED_CLASSES) { return $this->backend->getClasses($types); } /** * Returns if the broker contains a constant of the given name. * * @param string $constantName Constant name * @return boolean */ public function hasConstant($constantName) { return isset($this->cache[self::CACHE_CONSTANT][$constantName]) || $this->backend->hasConstant($constantName); } /** * Returns a reflection object of a constant (FQN expected). * * @param string $constantName Constant name * @return \TokenReflection\ReflectionConstant|null */ public function getConstant($constantName) { $constantName = ltrim($constantName, '\\'); if (isset($this->cache[self::CACHE_CONSTANT][$constantName])) { return $this->cache[self::CACHE_CONSTANT][$constantName]; } if ($constant = $this->backend->getConstant($constantName)) { $this->cache[self::CACHE_CONSTANT][$constantName] = $constant; } return $constant; } /** * Returns all constants from all namespaces. * * @return array */ public function getConstants() { return $this->backend->getConstants(); } /** * Returns if the broker contains a function of the given name. * * @param string $functionName Function name * @return boolean */ public function hasFunction($functionName) { return isset($this->cache[self::CACHE_FUNCTION][$functionName]) || $this->backend->hasFunction($functionName); } /** * Returns a reflection object of a function (FQN expected). * * @param string $functionName Function name * @return \TokenReflection\ReflectionFunction|null */ public function getFunction($functionName) { $functionName = ltrim($functionName, '\\'); if (isset($this->cache[self::CACHE_FUNCTION][$functionName])) { return $this->cache[self::CACHE_FUNCTION][$functionName]; } if ($function = $this->backend->getFunction($functionName)) { $this->cache[self::CACHE_FUNCTION][$functionName] = $function; } return $function; } /** * Returns all functions from all namespaces. * * @return array */ public function getFunctions() { return $this->backend->getFunctions(); } /** * Returns if the broker contains a file reflection of the given name. * * @param string $fileName File name * @return boolean */ public function hasFile($fileName) { return $this->backend->hasFile($fileName); } /** * Returns a reflection object of a file. * * @param string $fileName File name * @return \TokenReflection\ReflectionFile|null */ public function getFile($fileName) { return $this->backend->getFile($fileName); } /** * Returns all processed files reflections. * * @return array */ public function getFiles() { return $this->backend->getFiles(); } /** * Returns an array of tokens from a processed file. * * @param string $fileName File name * @return \TokenReflection\Stream\StreamBase|null */ public function getFileTokens($fileName) { return $this->backend->getFileTokens($fileName); } /** * Returns a real system path. * * @param string $path Source path * @return string|boolean */ public static function getRealPath($path) { if (0 === strpos($path, 'phar://')) { return is_file($path) || is_dir($path) ? $path : false; } else { return realpath($path); } } } PHP-Token-Reflection-1.4.0/TokenReflection/Broker/000077500000000000000000000000001237045466400216435ustar00rootroot00000000000000PHP-Token-Reflection-1.4.0/TokenReflection/Broker/Backend.php000066400000000000000000000112621237045466400237050ustar00rootroot00000000000000files[$fileName]); } /** * Returns a file reflection. * * @param string $fileName File name * @return \TokenReflection\ReflectionFile * @throws \TokenReflection\Exception\BrokerException If the requested file has not been processed */ public function getFile($fileName) { if (!isset($this->files[$fileName])) { throw new Exception\BrokerException($this->getBroker(), sprintf('File "%s" has not been processed.', $fileName), Exception\BrokerException::DOES_NOT_EXIST); } return $this->files[$fileName]; } /** * Returns file reflections. * * @return array */ public function getFiles() { return $this->files; } /** * Returns if there was such namespace processed (FQN expected). * * @param string $namespaceName Namespace name * @return boolean */ public function hasNamespace($namespaceName) { return isset($this->namespaces[ltrim($namespaceName, '\\')]); } /** * Returns a reflection object of the given namespace. * * @param string $namespaceName Namespace name * @return \TokenReflection\IReflectionNamespace * @throws \TokenReflection\Exception\BrokerException If the requested namespace does not exist. */ public function getNamespace($namespaceName) { if (!isset($this->namespaces[TokenReflection\ReflectionNamespace::NO_NAMESPACE_NAME])) { $this->namespaces[TokenReflection\ReflectionNamespace::NO_NAMESPACE_NAME] = new TokenReflection\ReflectionNamespace(TokenReflection\ReflectionNamespace::NO_NAMESPACE_NAME, $this->broker); } $namespaceName = ltrim($namespaceName, '\\'); if (!isset($this->namespaces[$namespaceName])) { throw new Exception\BrokerException($this->getBroker(), sprintf('Namespace %s does not exist.', $namespaceName), Exception\BrokerException::DOES_NOT_EXIST); } return $this->namespaces[$namespaceName]; } /** * Returns all present namespaces. * * @return array */ public function getNamespaces() { return $this->namespaces; } /** * Returns if there was such class processed (FQN expected). * * @param string $className Class name * @return boolean */ public function hasClass($className) { $className = ltrim($className, '\\'); if ($pos = strrpos($className, '\\')) { $namespace = substr($className, 0, $pos); if (!isset($this->namespaces[$namespace])) { return false; } $namespace = $this->getNamespace($namespace); $className = substr($className, $pos + 1); } else { $namespace = $this->getNamespace(TokenReflection\ReflectionNamespace::NO_NAMESPACE_NAME); } return $namespace->hasClass($className); } /** * Returns a reflection object of the given class (FQN expected). * * @param string $className CLass bame * @return \TokenReflection\IReflectionClass */ public function getClass($className) { if (empty($this->declaredClasses)) { $this->declaredClasses = array_flip(array_merge(get_declared_classes(), get_declared_interfaces())); } $className = ltrim($className, '\\'); try { $ns = $this->getNamespace( ($boundary = strrpos($className, '\\')) // Class within a namespace ? substr($className, 0, $boundary) // Class without a namespace : TokenReflection\ReflectionNamespace::NO_NAMESPACE_NAME ); return $ns->getClass($className); } catch (Exception\BaseException $e) { if (isset($this->declaredClasses[$className])) { $reflection = new Php\ReflectionClass($className, $this->broker); if ($reflection->isInternal()) { return $reflection; } } return new Dummy\ReflectionClass($className, $this->broker); } } /** * Returns all classes from all namespaces. * * @param integer $type Returned class types (multiple values may be OR-ed) * @return array */ public function getClasses($type = self::TOKENIZED_CLASSES) { if (null === $this->allClasses) { $this->allClasses = $this->parseClassLists(); } $result = array(); foreach ($this->allClasses as $classType => $classes) { if ($type & $classType) { $result = array_merge($result, $classes); } } return $result; } /** * Returns if there was such constant processed (FQN expected). * * @param string $constantName Constant name * @return boolean */ public function hasConstant($constantName) { $constantName = ltrim($constantName, '\\'); if ($pos = strpos($constantName, '::')) { $className = substr($constantName, 0, $pos); $constantName = substr($constantName, $pos + 2); if (!$this->hasClass($className)) { return false; } $parent = $this->getClass($className); } else { if ($pos = strrpos($constantName, '\\')) { $namespace = substr($constantName, 0, $pos); if (!$this->hasNamespace($namespace)) { return false; } $parent = $this->getNamespace($namespace); $constantName = substr($constantName, $pos + 1); } else { $parent = $this->getNamespace(TokenReflection\ReflectionNamespace::NO_NAMESPACE_NAME); } } return $parent->hasConstant($constantName); } /** * Returns a reflection object of a constant (FQN expected). * * @param string $constantName Constant name * @return \TokenReflection\IReflectionConstant * @throws \TokenReflection\Exception\RuntimeException If the requested constant does not exist. */ public function getConstant($constantName) { static $declared = array(); if (empty($declared)) { $declared = get_defined_constants(); } if ($boundary = strpos($constantName, '::')) { // Class constant $className = substr($constantName, 0, $boundary); $constantName = substr($constantName, $boundary + 2); return $this->getClass($className)->getConstantReflection($constantName); } try { $constantName = ltrim($constantName, '\\'); if ($boundary = strrpos($constantName, '\\')) { $ns = $this->getNamespace(substr($constantName, 0, $boundary)); $constantName = substr($constantName, $boundary + 1); } else { $ns = $this->getNamespace(TokenReflection\ReflectionNamespace::NO_NAMESPACE_NAME); } return $ns->getConstant($constantName); } catch (Exception\BaseException $e) { if (isset($declared[$constantName])) { $reflection = new Php\ReflectionConstant($constantName, $declared[$constantName], $this->broker); if ($reflection->isInternal()) { return $reflection; } } throw new Exception\BrokerException($this->getBroker(), sprintf('Constant %s does not exist.', $constantName), Exception\BrokerException::DOES_NOT_EXIST); } } /** * Returns all constants from all namespaces. * * @return array */ public function getConstants() { if (null === $this->allConstants) { $this->allConstants = array(); foreach ($this->namespaces as $namespace) { foreach ($namespace->getConstants() as $constant) { $this->allConstants[$constant->getName()] = $constant; } } } return $this->allConstants; } /** * Returns if there was such function processed (FQN expected). * * @param string $functionName Function name * @return boolean */ public function hasFunction($functionName) { $functionName = ltrim($functionName, '\\'); if ($pos = strrpos($functionName, '\\')) { $namespace = substr($functionName, 0, $pos); if (!isset($this->namespaces[$namespace])) { return false; } $namespace = $this->getNamespace($namespace); $functionName = substr($functionName, $pos + 1); } else { $namespace = $this->getNamespace(TokenReflection\ReflectionNamespace::NO_NAMESPACE_NAME); } return $namespace->hasFunction($functionName); } /** * Returns a reflection object of a function (FQN expected). * * @param string $functionName Function name * @return \TokenReflection\IReflectionFunction * @throws \TokenReflection\Exception\RuntimeException If the requested function does not exist. */ public function getFunction($functionName) { static $declared = array(); if (empty($declared)) { $functions = get_defined_functions(); $declared = array_flip($functions['internal']); } $functionName = ltrim($functionName, '\\'); try { $ns = $this->getNamespace( ($boundary = strrpos($functionName, '\\')) // Function within a namespace ? substr($functionName, 0, $boundary) // Function wihout a namespace : TokenReflection\ReflectionNamespace::NO_NAMESPACE_NAME ); return $ns->getFunction($functionName); } catch (Exception\BaseException $e) { if (isset($declared[$functionName])) { return new Php\ReflectionFunction($functionName, $this->broker); } throw new Exception\BrokerException($this->getBroker(), sprintf('Function %s does not exist.', $functionName), Exception\BrokerException::DOES_NOT_EXIST); } } /** * Returns all functions from all namespaces. * * @return array */ public function getFunctions() { if (null === $this->allFunctions) { $this->allFunctions = array(); foreach ($this->namespaces as $namespace) { foreach ($namespace->getFunctions() as $function) { $this->allFunctions[$function->getName()] = $function; } } } return $this->allFunctions; } /** * Returns if the given file was already processed. * * @param string $fileName File name * @return boolean */ public function isFileProcessed($fileName) { return isset($this->tokenStreams[Broker::getRealPath($fileName)]); } /** * Returns an array of tokens for a particular file. * * @param string $fileName File name * @return \TokenReflection\Stream\StreamBase * @throws \TokenReflection\Exception\BrokerException If the requested file was not processed. */ public function getFileTokens($fileName) { $realName = Broker::getRealPath($fileName); if (!isset($this->tokenStreams[$realName])) { throw new Exception\BrokerException($this->getBroker(), sprintf('File "%s" was not processed yet.', $fileName), Exception\BrokerException::DOES_NOT_EXIST); } return true === $this->tokenStreams[$realName] ? new FileStream($realName) : $this->tokenStreams[$realName]; } /** * Adds a file to the backend storage. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token stream * @param \TokenReflection\ReflectionFile $file File reflection object * @return \TokenReflection\Broker\Backend\Memory */ public function addFile(TokenReflection\Stream\StreamBase $tokenStream, TokenReflection\ReflectionFile $file) { $this->tokenStreams[$file->getName()] = $this->storingTokenStreams ? $tokenStream : true; $this->files[$file->getName()] = $file; $errors = array(); foreach ($file->getNamespaces() as $fileNamespace) { try { $namespaceName = $fileNamespace->getName(); if (!isset($this->namespaces[$namespaceName])) { $this->namespaces[$namespaceName] = new TokenReflection\ReflectionNamespace($namespaceName, $file->getBroker()); } $this->namespaces[$namespaceName]->addFileNamespace($fileNamespace); } catch (Exception\FileProcessingException $e) { $errors = array_merge($errors, $e->getReasons()); } catch (\Exception $e) { echo $e->getTraceAsString(); die($e->getMessage()); } } // Reset all-*-cache $this->allClasses = null; $this->allFunctions = null; $this->allConstants = null; if (!empty($errors)) { throw new Exception\FileProcessingException($errors, $file); } return $this; } /** * Sets the reflection broker instance. * * @param \TokenReflection\Broker $broker Reflection broker * @return \TokenReflection\Broker\Backend\Memory */ public function setBroker(Broker $broker) { $this->broker = $broker; return $this; } /** * Returns the reflection broker instance. * * @return \TokenReflection\Broker $broker Reflection broker */ public function getBroker() { return $this->broker; } /** * Sets if token streams are stored in the backend. * * @param boolean $store * @return \TokenReflection\Broker\Backend */ public function setStoringTokenStreams($store) { $this->storingTokenStreams = (bool) $store; return $this; } /** * Returns if token streams are stored in the backend. * * @return boolean */ public function getStoringTokenStreams() { return $this->storingTokenStreams; } /** * Prepares and returns used class lists. * * @return array */ protected function parseClassLists() { // Initialize the all-classes-cache $allClasses = array( self::TOKENIZED_CLASSES => array(), self::INTERNAL_CLASSES => array(), self::NONEXISTENT_CLASSES => array() ); foreach ($this->namespaces as $namespace) { foreach ($namespace->getClasses() as $class) { $allClasses[self::TOKENIZED_CLASSES][$class->getName()] = $class; } } foreach ($allClasses[self::TOKENIZED_CLASSES] as $className => $class) { foreach (array_merge($class->getParentClasses(), $class->getInterfaces()) as $parent) { if ($parent->isInternal()) { $allClasses[self::INTERNAL_CLASSES][$parent->getName()] = $parent; } elseif (!$parent->isTokenized()) { $allClasses[self::NONEXISTENT_CLASSES][$parent->getName()] = $parent; } } } return $allClasses; } } PHP-Token-Reflection-1.4.0/TokenReflection/Dummy/000077500000000000000000000000001237045466400215125ustar00rootroot00000000000000PHP-Token-Reflection-1.4.0/TokenReflection/Dummy/ReflectionClass.php000066400000000000000000000504231237045466400253070ustar00rootroot00000000000000name = ltrim($className, '\\'); $this->broker = $broker; } /** * Returns the name (FQN). * * @return string */ public function getName() { return $this->name; } /** * Returns an element pretty (docblock compatible) name. * * @return string */ public function getPrettyName() { return $this->name; } /** * Returns the unqualified name (UQN). * * @return string */ public function getShortName() { $pos = strrpos($this->name, '\\'); return false === $pos ? $this->name : substr($this->name, $pos + 1); } /** * Returns the namespace name. * * @return string */ public function getNamespaceName() { $pos = strrpos($this->name, '\\'); return false === $pos ? '' : substr($this->name, 0, $pos); } /** * Returns if the class is defined within a namespace. * * @return boolean */ public function inNamespace() { return false !== strrpos($this->name, '\\'); } /** * Returns imported namespaces and aliases from the declaring namespace. * * @return array */ public function getNamespaceAliases() { return array(); } /** * Returns the PHP extension reflection. * * @return null */ public function getExtension() { return null; } /** * Returns the PHP extension name. * * @return boolean */ public function getExtensionName() { return false; } /** * Returns the file name the reflection object is defined in. * * @return null */ public function getFileName() { return null; } /** * Returns a file reflection. * * @return \TokenReflection\ReflectionFile * @throws \TokenReflection\Exception\RuntimeException If the file is not stored inside the broker */ public function getFileReflection() { throw new Exception\BrokerException($this->getBroker(), sprintf('Class was not parsed from a file', $this->getName()), Exception\BrokerException::UNSUPPORTED); } /** * Returns the definition start line number in the file. * * @return null */ public function getStartLine() { return null; } /** * Returns the definition end line number in the file. * * @return null */ public function getEndLine() { return null; } /** * Returns the appropriate docblock definition. * * @return boolean */ public function getDocComment() { return false; } /** * Checks if there is a particular annotation. * * @param string $name Annotation name * @return boolean */ public function hasAnnotation($name) { return false; } /** * Returns a particular annotation value. * * @param string $name Annotation name * @return null */ public function getAnnotation($name) { return null; } /** * Returns parsed docblock. * * @return array */ public function getAnnotations() { return array(); } /** * Returns modifiers. * * @return integer */ public function getModifiers() { return 0; } /** * Returns if the class is abstract. * * @return boolean */ public function isAbstract() { return false; } /** * Returns if the class is final. * * @return boolean */ public function isFinal() { return false; } /** * Returns if the class is an interface. * * @return boolean */ public function isInterface() { return false; } /** * Returns if the class is an exception or its descendant. * * @return boolean */ public function isException() { return false; } /** * Returns if it is possible to create an instance of this class. * * @return boolean */ public function isInstantiable() { return false; } /** * Returns traits used by this class. * * @return array */ public function getTraits() { return array(); } /** * Returns traits used by this class and not its parents. * * @return array */ public function getOwnTraits() { return array(); } /** * Returns names of used traits. * * @return array */ public function getTraitNames() { return array(); } /** * Returns traits used by this class and not its parents. * * @return array */ public function getOwnTraitNames() { return array(); } /** * Returns method aliases from traits. * * @return array */ public function getTraitAliases() { return array(); } /** * Returns if the class is a trait. * * @return boolean */ public function isTrait() { return false; } /** * Returns if the class uses a particular trait. * * @param \ReflectionClass|\TokenReflection\IReflectionClass|string $trait Trait reflection or name * @return boolean */ public function usesTrait($trait) { return false; } /** * Returns if objects of this class are cloneable. * * Introduced in PHP 5.4. * * @return boolean * @see http://svn.php.net/viewvc/php/php-src/trunk/ext/reflection/php_reflection.c?revision=307971&view=markup#l4059 */ public function isCloneable() { return false; } /** * Returns if the class is iterateable. * * Returns true if the class implements the Traversable interface. * * @return boolean */ public function isIterateable() { return false; } /** * Returns if the reflection object is internal. * * @return boolean */ public function isInternal() { return false; } /** * Returns if the reflection object is user defined. * * @return boolean */ public function isUserDefined() { return false; } /** * Returns if the current reflection comes from a tokenized source. * * @return boolean */ public function isTokenized() { return false; } /** * Returns if the current class is a subclass of the given class. * * @param string|object $class Class name or reflection object * @return boolean */ public function isSubclassOf($class) { return false; } /** * Returns the parent class reflection. * * @return null */ public function getParentClass() { return false; } /** * Returns the parent classes reflections. * * @return array */ public function getParentClasses() { return array(); } /** * Returns the parent classes names. * * @return array */ public function getParentClassNameList() { return array(); } /** * Returns the parent class reflection. * * @return null */ public function getParentClassName() { return null; } /** * Returns if the class implements the given interface. * * @param string|object $interface Interface name or reflection object * @return boolean * @throws \TokenReflection\Exception\RuntimeException If the provided parameter is not an interface. */ public function implementsInterface($interface) { if (is_object($interface)) { if (!$interface instanceof IReflectionClass) { throw new Exception\RuntimeException(sprintf('Parameter must be a string or an instance of class reflection, "%s" provided.', get_class($interface)), Exception\RuntimeException::INVALID_ARGUMENT, $this); } $interfaceName = $interface->getName(); if (!$interface->isInterface()) { throw new Exception\RuntimeException(sprintf('"%s" is not an interface.', $interfaceName), Exception\RuntimeException::INVALID_ARGUMENT, $this); } } // Only validation, always returns false return false; } /** * Returns interface reflections. * * @return array */ public function getInterfaces() { return array(); } /** * Returns interface names. * * @return array */ public function getInterfaceNames() { return array(); } /** * Returns interfaces implemented by this class, not its parents. * * @return array */ public function getOwnInterfaces() { return array(); } /** * Returns names of interfaces implemented by this class, not its parents. * * @return array */ public function getOwnInterfaceNames() { return array(); } /** * Returns the class constructor reflection. * * @return null */ public function getConstructor() { return null; } /** * Returns the class desctructor reflection. * * @return null */ public function getDestructor() { return null; } /** * Returns if the class implements the given method. * * @param string $name Method name * @return boolean */ public function hasMethod($name) { return false; } /** * Returns a method reflection. * * @param string $name Method name * @throws \TokenReflection\Exception\RuntimeException If the requested method does not exist. */ public function getMethod($name) { throw new Exception\RuntimeException(sprintf('There is no method "%s".', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this); } /** * Returns method reflections. * * @param integer $filter Methods filter * @return array */ public function getMethods($filter = null) { return array(); } /** * Returns if the class implements (and not its parents) the given method. * * @param string $name Method name * @return boolean */ public function hasOwnMethod($name) { return false; } /** * Returns methods declared by this class, not its parents. * * @param integer $filter Methods filter * @return array */ public function getOwnMethods($filter = null) { return array(); } /** * Returns if the class imports the given method from traits. * * @param string $name Method name * @return boolean */ public function hasTraitMethod($name) { return false; } /** * Returns method reflections imported from traits. * * @param integer $filter Methods filter * @return array */ public function getTraitMethods($filter = null) { return array(); } /** * Returns if the class defines the given constant. * * @param string $name Constant name. * @return boolean */ public function hasConstant($name) { return false; } /** * Returns a constant value. * * @param string $name Constant name * @throws \TokenReflection\Exception\RuntimeException If the requested constant does not exist. */ public function getConstant($name) { throw new Exception\RuntimeException(sprintf('There is no constant "%s".', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this); } /** * Returns a constant reflection. * * @param string $name Constant name * @throws \TokenReflection\Exception\RuntimeException If the requested constant does not exist. */ public function getConstantReflection($name) { throw new Exception\RuntimeException(sprintf('There is no constant "%s".', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this); } /** * Returns an array of constant values. * * @return array */ public function getConstants() { return array(); } /** * Returns an array of constant reflections. * * @return array */ public function getConstantReflections() { return array(); } /** * Returns if the class (and not its parents) defines the given constant. * * @param string $name Constant name. * @return boolean */ public function hasOwnConstant($name) { return false; } /** * Returns constants declared by this class, not its parents. * * @return array */ public function getOwnConstants() { return array(); } /** * Returns an array of constant reflections defined by this class not its parents. * * @return array */ public function getOwnConstantReflections() { return array(); } /** * Returns default properties. * * @return array */ public function getDefaultProperties() { return array(); } /** * Returns if the class implements the given property. * * @param string $name Property name * @return boolean */ public function hasProperty($name) { return false; } /** * Returns class properties. * * @param integer $filter Property types * @return array */ public function getProperties($filter = null) { return array(); } /** * Return a property reflections. * * @param string $name Property name * @throws \TokenReflection\Exception\RuntimeException If the requested property does not exist. */ public function getProperty($name) { throw new Exception\RuntimeException(sprintf('There is no property "%s".', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this); } /** * Returns if the class (and not its parents) implements the given property. * * @param string $name Property name * @return boolean */ public function hasOwnProperty($name) { return false; } /** * Returns properties declared by this class, not its parents. * * @param integer $filter Properties filter * @return array */ public function getOwnProperties($filter = null) { return array(); } /** * Returns if the class imports the given property from traits. * * @param string $name Property name * @return boolean */ public function hasTraitProperty($name) { return false; } /** * Returns property reflections imported from traits. * * @param integer $filter Properties filter * @return array */ public function getTraitProperties($filter = null) { return array(); } /** * Returns static properties reflections. * * @return array */ public function getStaticProperties() { return array(); } /** * Returns a value of a static property. * * @param string $name Property name * @param mixed $default Default value * @throws \TokenReflection\Exception\RuntimeException If the requested static property does not exist. */ public function getStaticPropertyValue($name, $default = null) { throw new Exception\RuntimeException(sprintf('There is no static property "%s".', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this); } /** * Returns reflections of direct subclasses. * * @return array */ public function getDirectSubclasses() { return array(); } /** * Returns names of direct subclasses. * * @return array */ public function getDirectSubclassNames() { return array(); } /** * Returns reflections of indirect subclasses. * * @return array */ public function getIndirectSubclasses() { return array(); } /** * Returns names of indirect subclasses. * * @return array */ public function getIndirectSubclassNames() { return array(); } /** * Returns reflections of classes directly implementing this interface. * * @return array */ public function getDirectImplementers() { return array(); } /** * Returns names of classes directly implementing this interface. * * @return array */ public function getDirectImplementerNames() { return array(); } /** * Returns reflections of classes indirectly implementing this interface. * * @return array */ public function getIndirectImplementers() { return array(); } /** * Returns names of classes indirectly implementing this interface. * * @return array */ public function getIndirectImplementerNames() { return array(); } /** * Returns if the given object is an instance of this class. * * @param object $object Instance * @return boolean * @throws \TokenReflection\Exception\RuntimeException If the provided argument is not an object. */ public function isInstance($object) { if (!is_object($object)) { throw new Exception\RuntimeException(sprintf('Parameter must be a class instance, "%s" provided.', gettype($object)), Exception\RuntimeException::INVALID_ARGUMENT, $this); } return $this->name === get_class($object) || is_subclass_of($object, $this->name); } /** * Creates a new class instance without using a constructor. * * @return object * @throws \TokenReflection\Exception\RuntimeException If the class inherits from an internal class. */ public function newInstanceWithoutConstructor() { if (!class_exists($this->name, true)) { throw new Exception\RuntimeException('Could not create an instance; class does not exist.', Exception\RuntimeException::DOES_NOT_EXIST, $this); } $reflection = new \TokenReflection\Php\ReflectionClass($this->name, $this->getBroker()); return $reflection->newInstanceWithoutConstructor(); } /** * Creates a new instance using variable number of parameters. * * Use any number of constructor parameters as function parameters. * * @param mixed $args * @return object */ public function newInstance($args) { return $this->newInstanceArgs(func_get_args()); } /** * Creates a new instance using an array of parameters. * * @param array $args Array of constructor parameters * @return object * @throws \TokenReflection\Exception\RuntimeException If the required class does not exist. */ public function newInstanceArgs(array $args = array()) { if (!class_exists($this->name, true)) { throw new Exception\RuntimeException('Could not create an instance of class; class does not exist.', Exception\RuntimeException::DOES_NOT_EXIST, $this); } $reflection = new InternalReflectionClass($this->name); return $reflection->newInstanceArgs($args); } /** * Sets a static property value. * * @param string $name Property name * @param mixed $value Property value * @throws \TokenReflection\Exception\RuntimeException If the requested static property does not exist. */ public function setStaticPropertyValue($name, $value) { throw new Exception\RuntimeException(sprintf('There is no static property "%s".', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this); } /** * Returns the string representation of the reflection object. * * @return string */ public function __toString() { return sprintf( "Class|Interface [ class|interface %s ] {\n %s%s%s%s%s\n}\n", $this->getName(), "\n\n - Constants [0] {\n }", "\n\n - Static properties [0] {\n }", "\n\n - Static methods [0] {\n }", "\n\n - Properties [0] {\n }", "\n\n - Methods [0] {\n }" ); } /** * Exports a reflected object. * * @param \TokenReflection\Broker $broker Broker instance * @param string|object $className Class name or class instance * @param boolean $return Return the export instead of outputting it * @return string|null * @throws \TokenReflection\Exception\RuntimeException If requested parameter doesn't exist. */ public static function export(Broker $broker, $className, $return = false) { TokenReflection\ReflectionClass::export($broker, $className, $return); } /** * Outputs the reflection subject source code. * * @return string */ public function getSource() { return ''; } /** * Returns the start position in the file token stream. * * @return integer */ public function getStartPosition() { return -1; } /** * Returns the end position in the file token stream. * * @return integer */ public function getEndPosition() { return -1; } /** * Returns if the class definition is complete. * * Dummy classes never have the definition complete. * * @return boolean */ public function isComplete() { return false; } /** * Returns if the class definition is valid. * * Dummy classes are always valid. * * @return boolean */ public function isValid() { return true; } /** * Returns if the reflection subject is deprecated. * * @return boolean */ public function isDeprecated() { return false; } /** * Returns the reflection broker used by this reflection object. * * @return \TokenReflection\Broker */ public function getBroker() { return $this->broker; } /** * Magic __get method. * * @param string $key Variable name * @return mixed */ final public function __get($key) { return ReflectionBase::get($this, $key); } /** * Magic __isset method. * * @param string $key Variable name * @return boolean */ final public function __isset($key) { return ReflectionBase::exists($this, $key); } } PHP-Token-Reflection-1.4.0/TokenReflection/Exception/000077500000000000000000000000001237045466400223555ustar00rootroot00000000000000PHP-Token-Reflection-1.4.0/TokenReflection/Exception/BaseException.php000066400000000000000000000033241237045466400256210ustar00rootroot00000000000000getDetail(); return sprintf( "exception '%s'%s in %s on line %d\n%s\nStack trace:\n%s", get_class($this), $this->getMessage() ? " with message '" . $this->getMessage() . "'" : '', $this->getFile(), $this->getLine(), empty($detail) ? '' : $detail . "\n", $this->getTraceAsString() ); } /** * Returns the exception details as string. * * @return string */ final public function __toString() { $output = ''; if ($ex = $this->getPrevious()) { $output .= (string) $ex . "\n\nNext "; } return $output . $this->getOutput() . "\n"; } } PHP-Token-Reflection-1.4.0/TokenReflection/Exception/BrokerException.php000066400000000000000000000023021237045466400261660ustar00rootroot00000000000000broker = $broker; } /** * Returns the current Broker. * * @return \TokenReflection\Broker */ public function getBroker() { return $this->broker; } /** * Returns an exception description detail. * * @return string */ public function getDetail() { return ''; } } PHP-Token-Reflection-1.4.0/TokenReflection/Exception/FileProcessingException.php000066400000000000000000000032201237045466400276560ustar00rootroot00000000000000getName()), 0, $sender ); $this->reasons = $reasons; } /** * Returns a list of reasons why the file could not be processed. * * @return array */ public function getReasons() { return $this->reasons; } /** * Returns an exception description detail. * * @return string */ public function getDetail() { if (!empty($this->reasons)) { $reasons = array_map(function(BaseException $reason) { if ($reason instanceof ParseException) { return $reason->getDetail(); } else { return $reason->getMessage(); } }, $this->reasons); return "There were following reasons for this exception:\n" . implode("\n", $reasons); } return ''; } } PHP-Token-Reflection-1.4.0/TokenReflection/Exception/ParseException.php000066400000000000000000000132311237045466400260170ustar00rootroot00000000000000sender = $sender; $token = $tokenStream->current(); $position = $tokenStream->key(); if (!empty($token) && !empty($position)) { $this->token = $token; $this->tokenName = $tokenStream->getTokenName(); $line = $this->token[2]; $min = $max = $position; } else { $min = $max = $tokenStream->count() - 1; $line = $tokenStream[$min][2]; } $this->exceptionLine = $line; static $skip = array(T_WHITESPACE => true, T_COMMENT => true, T_DOC_COMMENT => true); $significant = array(); while (isset($tokenStream[$min - 1])) { if (!isset($significant[$tokenStream[$min][2]])) { if (self::SOURCE_LINES_AROUND <= array_sum($significant)) { break; } $significant[$tokenStream[$min][2]] = !isset($skip[$tokenStream[$min][0]]); } else { $significant[$tokenStream[$min][2]] |= !isset($skip[$tokenStream[$min][0]]); } $min--; } $significant = array(); while (isset($tokenStream[$max + 1])) { if (!isset($significant[$tokenStream[$max][2]])) { if (self::SOURCE_LINES_AROUND <= array_sum($significant)) { break; } $significant[$tokenStream[$max][2]] = !isset($skip[$tokenStream[$max][0]]); } else { $significant[$tokenStream[$max][2]] |= !isset($skip[$tokenStream[$max][0]]); } $max++; } $this->scopeBoundaries = array($min, $max); } /** * Returns the token where the problem was detected or NULL if the token stream was empty or an end was reached. * * @return array|null */ public function getToken() { return $this->token; } /** * Returns the name of the token where the problem was detected or NULL if the token stream was empty or an end was reached. * * @return string|null */ public function getTokenName() { return $this->tokenName; } /** * Returns the line where the exception was thrown. * * @return integer */ public function getExceptionLine() { return $this->exceptionLine; } /** * Returns the file line with the token or null. * * @return integer|null */ public function getTokenLine() { return null === $this->token ? null : $this->token[2]; } /** * Returns the source code part around the token. * * @param boolean $lineNumbers Returns the source code part with line numbers * @return string|null */ public function getSourcePart($lineNumbers = false) { if (empty($this->scopeBoundaries)) { return null; } list($lo, $hi) = $this->scopeBoundaries; $stream = $this->getStream(); $code = $stream->getSourcePart($lo, $hi); if ($lineNumbers) { $lines = explode("\n", $code); $startLine = $stream[$lo][2]; $width = strlen($startLine + count($lines) - 1); $errorLine = $this->token[2]; $actualLine = $startLine; $code = implode( "\n", array_map(function($line) use (&$actualLine, $width, $errorLine) { return ($actualLine === $errorLine ? '*' : ' ') . str_pad($actualLine++, $width, ' ', STR_PAD_LEFT) . ': ' . $line; }, $lines) ); } return $code; } /** * Returns the reflection element that caused the exception to be raised. * * @return \TokenReflection\IReflection */ public function getSender() { return $this->sender; } /** * Returns an exception description detail. * * @return string */ public function getDetail() { if (0 === $this->getStream()->count()) { return parent::getDetail() . 'The token stream was empty.'; } elseif (empty($this->token)) { return parent::getDetail() . 'The token stream was read out of its bounds.'; } else { return parent::getDetail() . sprintf( "\nThe cause of the exception was the %s token (line %s) in following part of %s source code:\n\n%s", $this->tokenName, $this->token[2], $this->sender && $this->sender->getName() ? $this->sender->getPrettyName() : 'the', $this->getSourcePart(true) ); } } } PHP-Token-Reflection-1.4.0/TokenReflection/Exception/RuntimeException.php000066400000000000000000000026401237045466400263720ustar00rootroot00000000000000sender = $sender; } /** * Returns the reflection element that caused the exception to be raised. * * @return \TokenReflection\IReflection */ public function getSender() { return $this->sender; } /** * Returns an exception description detail. * * @return string */ public function getDetail() { return null === $this->sender ? '' : sprintf('Thrown when working with "%s".', $this->sender->getPrettyName()); } } PHP-Token-Reflection-1.4.0/TokenReflection/Exception/StreamException.php000066400000000000000000000034151237045466400262030ustar00rootroot00000000000000stream = $stream; } /** * Returns the reflection element that caused the exception to be raised. * * @return \TokenReflection\Stream\StreamBase */ public function getStream() { return $this->stream; } /** * Returns the processed file name. * * @return string */ public function getFileName() { return $this->stream->getFileName(); } /** * Returns an exception description detail. * * @return string */ public function getDetail() { return sprintf('Thrown when working with file "%s" token stream.', $this->getFileName()); } } PHP-Token-Reflection-1.4.0/TokenReflection/IReflection.php000066400000000000000000000024731237045466400233410ustar00rootroot00000000000000 5.3.0, you can uncomment it. * * @return mixed */ // public function invoke(); /** * Calls the function. * * @param array $args Function parameter values * @return mixed */ public function invokeArgs(array $args); /** * Returns the function/method as closure. * * @return \Closure */ public function getClosure(); /** * Returns if the function definition is valid. * * That means that the source code is valid and the function name is unique within parsed files. * * @return boolean */ public function isValid(); /** * Returns imported namespaces and aliases from the declaring namespace. * * @return array */ public function getNamespaceAliases(); } PHP-Token-Reflection-1.4.0/TokenReflection/IReflectionFunctionBase.php000066400000000000000000000045721237045466400256440ustar00rootroot00000000000000name = ltrim($className, '\\'); $this->fileName = $fileName; $this->broker = $broker; } /** * Returns the name (FQN). * * @return string */ public function getName() { return $this->name; } /** * Returns an element pretty (docblock compatible) name. * * @return string */ public function getPrettyName() { return $this->name; } /** * Returns the unqualified name (UQN). * * @return string */ public function getShortName() { $pos = strrpos($this->name, '\\'); return false === $pos ? $this->name : substr($this->name, $pos + 1); } /** * Returns the namespace name. * * @return string */ public function getNamespaceName() { $pos = strrpos($this->name, '\\'); return false === $pos ? '' : substr($this->name, 0, $pos); } /** * Returns if the class is defined within a namespace. * * @return boolean */ public function inNamespace() { return false !== strrpos($this->name, '\\'); } /** * Returns imported namespaces and aliases from the declaring namespace. * * @return array */ public function getNamespaceAliases() { return array(); } /** * Returns the PHP extension reflection. * * @return null */ public function getExtension() { return null; } /** * Returns the PHP extension name. * * @return boolean */ public function getExtensionName() { return false; } /** * Returns the file name the reflection object is defined in. * * @return null */ public function getFileName() { return $this->fileName; } /** * Returns a file reflection. * * @return \TokenReflection\ReflectionFile * @throws \TokenReflection\Exception\RuntimeException If the file is not stored inside the broker */ public function getFileReflection() { throw new Exception\BrokerException($this->getBroker(), sprintf('Class was not parsed from a file', $this->getName()), Exception\BrokerException::UNSUPPORTED); } /** * Returns the definition start line number in the file. * * @return null */ public function getStartLine() { return null; } /** * Returns the definition end line number in the file. * * @return null */ public function getEndLine() { return null; } /** * Returns the appropriate docblock definition. * * @return boolean */ public function getDocComment() { return false; } /** * Checks if there is a particular annotation. * * @param string $name Annotation name * @return boolean */ public function hasAnnotation($name) { return false; } /** * Returns a particular annotation value. * * @param string $name Annotation name * @return null */ public function getAnnotation($name) { return null; } /** * Returns parsed docblock. * * @return array */ public function getAnnotations() { return array(); } /** * Returns modifiers. * * @return integer */ public function getModifiers() { return 0; } /** * Returns if the class is abstract. * * @return boolean */ public function isAbstract() { return false; } /** * Returns if the class is final. * * @return boolean */ public function isFinal() { return false; } /** * Returns if the class is an interface. * * @return boolean */ public function isInterface() { return false; } /** * Returns if the class is an exception or its descendant. * * @return boolean */ public function isException() { return false; } /** * Returns if it is possible to create an instance of this class. * * @return boolean */ public function isInstantiable() { return false; } /** * Returns traits used by this class. * * @return array */ public function getTraits() { return array(); } /** * Returns traits used by this class and not its parents. * * @return array */ public function getOwnTraits() { return array(); } /** * Returns names of used traits. * * @return array */ public function getTraitNames() { return array(); } /** * Returns traits used by this class and not its parents. * * @return array */ public function getOwnTraitNames() { return array(); } /** * Returns method aliases from traits. * * @return array */ public function getTraitAliases() { return array(); } /** * Returns if the class is a trait. * * @return boolean */ public function isTrait() { return false; } /** * Returns if the class uses a particular trait. * * @param \ReflectionClass|\TokenReflection\IReflectionClass|string $trait Trait reflection or name * @return boolean */ public function usesTrait($trait) { return false; } /** * Returns if objects of this class are cloneable. * * Introduced in PHP 5.4. * * @return boolean * @see http://svn.php.net/viewvc/php/php-src/trunk/ext/reflection/php_reflection.c?revision=307971&view=markup#l4059 */ public function isCloneable() { return false; } /** * Returns if the class is iterateable. * * Returns true if the class implements the Traversable interface. * * @return boolean */ public function isIterateable() { return false; } /** * Returns if the reflection object is internal. * * @return boolean */ public function isInternal() { return false; } /** * Returns if the reflection object is user defined. * * @return boolean */ public function isUserDefined() { return true; } /** * Returns if the current reflection comes from a tokenized source. * * @return boolean */ public function isTokenized() { return true; } /** * Returns if the current class is a subclass of the given class. * * @param string|object $class Class name or reflection object * @return boolean */ public function isSubclassOf($class) { return false; } /** * Returns the parent class reflection. * * @return null */ public function getParentClass() { return false; } /** * Returns the parent classes reflections. * * @return array */ public function getParentClasses() { return array(); } /** * Returns the parent classes names. * * @return array */ public function getParentClassNameList() { return array(); } /** * Returns the parent class reflection. * * @return null */ public function getParentClassName() { return null; } /** * Returns if the class implements the given interface. * * @param string|object $interface Interface name or reflection object * @return boolean * @throws \TokenReflection\Exception\RuntimeException If the provided parameter is not an interface. */ public function implementsInterface($interface) { if (is_object($interface)) { if (!$interface instanceof IReflectionClass) { throw new Exception\RuntimeException(sprintf('Parameter must be a string or an instance of class reflection, "%s" provided.', get_class($interface)), Exception\RuntimeException::INVALID_ARGUMENT, $this); } $interfaceName = $interface->getName(); if (!$interface->isInterface()) { throw new Exception\RuntimeException(sprintf('"%s" is not an interface.', $interfaceName), Exception\RuntimeException::INVALID_ARGUMENT, $this); } } // Only validation, always returns false return false; } /** * Returns interface reflections. * * @return array */ public function getInterfaces() { return array(); } /** * Returns interface names. * * @return array */ public function getInterfaceNames() { return array(); } /** * Returns interfaces implemented by this class, not its parents. * * @return array */ public function getOwnInterfaces() { return array(); } /** * Returns names of interfaces implemented by this class, not its parents. * * @return array */ public function getOwnInterfaceNames() { return array(); } /** * Returns the class constructor reflection. * * @return null */ public function getConstructor() { return null; } /** * Returns the class desctructor reflection. * * @return null */ public function getDestructor() { return null; } /** * Returns if the class implements the given method. * * @param string $name Method name * @return boolean */ public function hasMethod($name) { return false; } /** * Returns a method reflection. * * @param string $name Method name * @throws \TokenReflection\Exception\RuntimeException If the requested method does not exist. */ public function getMethod($name) { throw new Exception\RuntimeException(sprintf('There is no method "%s".', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this); } /** * Returns method reflections. * * @param integer $filter Methods filter * @return array */ public function getMethods($filter = null) { return array(); } /** * Returns if the class implements (and not its parents) the given method. * * @param string $name Method name * @return boolean */ public function hasOwnMethod($name) { return false; } /** * Returns methods declared by this class, not its parents. * * @param integer $filter Methods filter * @return array */ public function getOwnMethods($filter = null) { return array(); } /** * Returns if the class imports the given method from traits. * * @param string $name Method name * @return boolean */ public function hasTraitMethod($name) { return false; } /** * Returns method reflections imported from traits. * * @param integer $filter Methods filter * @return array */ public function getTraitMethods($filter = null) { return array(); } /** * Returns if the class defines the given constant. * * @param string $name Constant name. * @return boolean */ public function hasConstant($name) { return false; } /** * Returns a constant value. * * @param string $name Constant name * @throws \TokenReflection\Exception\RuntimeException If the requested constant does not exist. */ public function getConstant($name) { throw new Exception\RuntimeException(sprintf('There is no constant "%s".', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this); } /** * Returns a constant reflection. * * @param string $name Constant name * @throws \TokenReflection\Exception\RuntimeException If the requested constant does not exist. */ public function getConstantReflection($name) { throw new Exception\RuntimeException(sprintf('There is no constant "%s".', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this); } /** * Returns an array of constant values. * * @return array */ public function getConstants() { return array(); } /** * Returns an array of constant reflections. * * @return array */ public function getConstantReflections() { return array(); } /** * Returns if the class (and not its parents) defines the given constant. * * @param string $name Constant name. * @return boolean */ public function hasOwnConstant($name) { return false; } /** * Returns constants declared by this class, not its parents. * * @return array */ public function getOwnConstants() { return array(); } /** * Returns an array of constant reflections defined by this class not its parents. * * @return array */ public function getOwnConstantReflections() { return array(); } /** * Returns default properties. * * @return array */ public function getDefaultProperties() { return array(); } /** * Returns if the class implements the given property. * * @param string $name Property name * @return boolean */ public function hasProperty($name) { return false; } /** * Returns class properties. * * @param integer $filter Property types * @return array */ public function getProperties($filter = null) { return array(); } /** * Return a property reflections. * * @param string $name Property name * @throws \TokenReflection\Exception\RuntimeException If the requested property does not exist. */ public function getProperty($name) { throw new Exception\RuntimeException(sprintf('There is no property "%s".', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this); } /** * Returns if the class (and not its parents) implements the given property. * * @param string $name Property name * @return boolean */ public function hasOwnProperty($name) { return false; } /** * Returns properties declared by this class, not its parents. * * @param integer $filter Properties filter * @return array */ public function getOwnProperties($filter = null) { return array(); } /** * Returns if the class imports the given property from traits. * * @param string $name Property name * @return boolean */ public function hasTraitProperty($name) { return false; } /** * Returns property reflections imported from traits. * * @param integer $filter Properties filter * @return array */ public function getTraitProperties($filter = null) { return array(); } /** * Returns static properties reflections. * * @return array */ public function getStaticProperties() { return array(); } /** * Returns a value of a static property. * * @param string $name Property name * @param mixed $default Default value * @throws \TokenReflection\Exception\RuntimeException If the requested static property does not exist. */ public function getStaticPropertyValue($name, $default = null) { throw new Exception\RuntimeException(sprintf('There is no static property "%s".', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this); } /** * Returns reflections of direct subclasses. * * @return array */ public function getDirectSubclasses() { return array(); } /** * Returns names of direct subclasses. * * @return array */ public function getDirectSubclassNames() { return array(); } /** * Returns reflections of indirect subclasses. * * @return array */ public function getIndirectSubclasses() { return array(); } /** * Returns names of indirect subclasses. * * @return array */ public function getIndirectSubclassNames() { return array(); } /** * Returns reflections of classes directly implementing this interface. * * @return array */ public function getDirectImplementers() { return array(); } /** * Returns names of classes directly implementing this interface. * * @return array */ public function getDirectImplementerNames() { return array(); } /** * Returns reflections of classes indirectly implementing this interface. * * @return array */ public function getIndirectImplementers() { return array(); } /** * Returns names of classes indirectly implementing this interface. * * @return array */ public function getIndirectImplementerNames() { return array(); } /** * Returns if the given object is an instance of this class. * * @param object $object Instance * @return boolean * @throws \TokenReflection\Exception\RuntimeException If the provided argument is not an object. */ public function isInstance($object) { if (!is_object($object)) { throw new Exception\RuntimeException(sprintf('Parameter must be a class instance, "%s" provided.', gettype($object)), Exception\RuntimeException::INVALID_ARGUMENT, $this); } return $this->name === get_class($object) || is_subclass_of($object, $this->name); } /** * Creates a new class instance without using a constructor. * * @return object * @throws \TokenReflection\Exception\RuntimeException If the class inherits from an internal class. */ public function newInstanceWithoutConstructor() { if (!class_exists($this->name, true)) { throw new Exception\RuntimeException('Could not create an instance; class does not exist.', Exception\RuntimeException::DOES_NOT_EXIST, $this); } $reflection = new \TokenReflection\Php\ReflectionClass($this->name, $this->getBroker()); return $reflection->newInstanceWithoutConstructor(); } /** * Creates a new instance using variable number of parameters. * * Use any number of constructor parameters as function parameters. * * @param mixed $args * @return object */ public function newInstance($args) { return $this->newInstanceArgs(func_get_args()); } /** * Creates a new instance using an array of parameters. * * @param array $args Array of constructor parameters * @return object * @throws \TokenReflection\Exception\RuntimeException If the required class does not exist. */ public function newInstanceArgs(array $args = array()) { if (!class_exists($this->name, true)) { throw new Exception\RuntimeException('Could not create an instance of class; class does not exist.', Exception\RuntimeException::DOES_NOT_EXIST, $this); } $reflection = new InternalReflectionClass($this->name); return $reflection->newInstanceArgs($args); } /** * Sets a static property value. * * @param string $name Property name * @param mixed $value Property value * @throws \TokenReflection\Exception\RuntimeException If the requested static property does not exist. */ public function setStaticPropertyValue($name, $value) { throw new Exception\RuntimeException(sprintf('There is no static property "%s".', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this); } /** * Returns the string representation of the reflection object. * * @return string */ public function __toString() { return sprintf( "Class|Interface [ class|interface %s ] {\n %s%s%s%s%s\n}\n", $this->getName(), "\n\n - Constants [0] {\n }", "\n\n - Static properties [0] {\n }", "\n\n - Static methods [0] {\n }", "\n\n - Properties [0] {\n }", "\n\n - Methods [0] {\n }" ); } /** * Exports a reflected object. * * @param \TokenReflection\Broker $broker Broker instance * @param string|object $className Class name or class instance * @param boolean $return Return the export instead of outputting it * @return string|null * @throws \TokenReflection\Exception\RuntimeException If requested parameter doesn't exist. */ public static function export(Broker $broker, $className, $return = false) { TokenReflection\ReflectionClass::export($broker, $className, $return); } /** * Outputs the reflection subject source code. * * @return string */ public function getSource() { return ''; } /** * Returns the start position in the file token stream. * * @return integer */ public function getStartPosition() { return -1; } /** * Returns the end position in the file token stream. * * @return integer */ public function getEndPosition() { return -1; } /** * Returns if the class definition is complete. * * Invalid classes are always complete. * * @return boolean */ public function isComplete() { return true; } /** * Returns if the class definition is valid. * * @return boolean */ public function isValid() { return false; } /** * Returns if the reflection subject is deprecated. * * @return boolean */ public function isDeprecated() { return false; } /** * Returns the reflection broker used by this reflection object. * * @return \TokenReflection\Broker */ public function getBroker() { return $this->broker; } /** * Magic __get method. * * @param string $key Variable name * @return mixed */ final public function __get($key) { return ReflectionBase::get($this, $key); } /** * Magic __isset method. * * @param string $key Variable name * @return boolean */ final public function __isset($key) { return ReflectionBase::exists($this, $key); } } PHP-Token-Reflection-1.4.0/TokenReflection/Invalid/ReflectionConstant.php000066400000000000000000000145421237045466400263300ustar00rootroot00000000000000name = $name; $this->broker = $broker; $this->fileName = $fileName; } /** * Returns the name. * * @return string */ public function getName() { return $this->name; } /** * Returns the unqualified name (UQN). * * @return string */ public function getShortName() { $pos = strrpos($this->name, '\\'); return false === $pos ? $this->name : substr($this->name, $pos + 1); } /** * Returns the declaring class reflection. * * @return null */ public function getDeclaringClass() { return null; } /** * Returns the declaring class name. * * @return null */ public function getDeclaringClassName() { return null; } /** * Returns the namespace name. * * @return string */ public function getNamespaceName() { $pos = strrpos($this->name, '\\'); return false === $pos ? '' : substr($this->name, 0, $pos); } /** * Returns if the function/method is defined within a namespace. * * @return boolean */ public function inNamespace() { return false !== strpos($this->name, '\\'); } /** * Returns the PHP extension reflection. * * @return null */ public function getExtension() { return null; } /** * Returns the PHP extension name. * * @return boolean */ public function getExtensionName() { return false; } /** * Returns the appropriate source code part. * * @return string */ public function getSource() { return ''; } /** * Returns the start position in the file token stream. * * @return integer */ public function getStartPosition() { return -1; } /** * Returns the end position in the file token stream. * * @return integer */ public function getEndPosition() { return -1; } /** * Returns the file name the reflection object is defined in. * * @return null */ public function getFileName() { return $this->fileName; } /** * Returns a file reflection. * * @return \TokenReflection\ReflectionFile * @throws \TokenReflection\Exception\RuntimeException If the file is not stored inside the broker */ public function getFileReflection() { throw new Exception\BrokerException($this->getBroker(), sprintf('Constant %s was not parsed from a file', $this->getPrettyName()), Exception\BrokerException::UNSUPPORTED); } /** * Returns the definition start line number in the file. * * @return null */ public function getStartLine() { return null; } /** * Returns the definition end line number in the file. * * @return null */ public function getEndLine() { return null; } /** * Returns the appropriate docblock definition. * * @return boolean */ public function getDocComment() { return false; } /** * Checks if there is a particular annotation. * * @param string $name Annotation name * @return boolean */ public function hasAnnotation($name) { return false; } /** * Returns a particular annotation value. * * @param string $name Annotation name * @return null */ public function getAnnotation($name) { return null; } /** * Returns parsed docblock. * * @return array */ public function getAnnotations() { return array(); } /** * Returns the constant value. * * @return mixed */ public function getValue() { return null; } /** * Returns the part of the source code defining the constant value. * * @return string */ public function getValueDefinition() { return null; } /** * Returns the originaly provided value definition. * * @return string */ public function getOriginalValueDefinition() { return null; } /** * Returns if the constant is internal. * * @return boolean */ public function isInternal() { return false; } /** * Returns if the constant is user defined. * * @return boolean */ public function isUserDefined() { return true; } /** * Returns if the current reflection comes from a tokenized source. * * @return boolean */ public function isTokenized() { return true; } /** * Returns if the reflection subject is deprecated. * * @return boolean */ public function isDeprecated() { return false; } /** * Returns an element pretty (docblock compatible) name. * * @return string */ public function getPrettyName() { return $this->name; } /** * Returns the string representation of the reflection object. * * @return string */ public function __toString() { return sprintf( "Constant [ %s %s ] { %s }\n", gettype(null), $this->getName(), null ); } /** * Returns the reflection broker used by this reflection object. * * @return \TokenReflection\Broker */ public function getBroker() { return $this->broker; } /** * Returns imported namespaces and aliases from the declaring namespace. * * @return array */ public function getNamespaceAliases() { return array(); } /** * Returns if the constant definition is valid. * * @return boolean */ public function isValid() { return false; } /** * Magic __get method. * * @param string $key Variable name * @return mixed */ final public function __get($key) { return ReflectionBase::get($this, $key); } /** * Magic __isset method. * * @param string $key Variable name * @return boolean */ final public function __isset($key) { return ReflectionBase::exists($this, $key); } } PHP-Token-Reflection-1.4.0/TokenReflection/Invalid/ReflectionElement.php000066400000000000000000000017551237045466400261320ustar00rootroot00000000000000reasons[] = $reason; return $this; } /** * Returns a list of reasons why this element's reflection is invalid. * * @return array */ public function getReasons() { return $this->reasons; } /** * Returns if there are any known reasons why this element's reflection is invalid. * * @return boolean */ public function hasReasons() { return !empty($this->reasons); } } PHP-Token-Reflection-1.4.0/TokenReflection/Invalid/ReflectionFunction.php000066400000000000000000000204771237045466400263300ustar00rootroot00000000000000name = ltrim($name, '\\'); $this->broker = $broker; $this->fileName = $fileName; } /** * Returns the name (FQN). * * @return string */ public function getName() { return $this->name; } /** * Returns the unqualified name (UQN). * * @return string */ public function getShortName() { $pos = strrpos($this->name, '\\'); return false === $pos ? $this->name : substr($this->name, $pos + 1); } /** * Returns the namespace name. * * @return string */ public function getNamespaceName() { $pos = strrpos($this->name, '\\'); return false === $pos ? '' : substr($this->name, 0, $pos); } /** * Returns if the class is defined within a namespace. * * @return boolean */ public function inNamespace() { return false !== strrpos($this->name, '\\'); } /** * Returns if the reflection object is internal. * * @return boolean */ public function isInternal() { return false; } /** * Returns if the reflection object is user defined. * * @return boolean */ public function isUserDefined() { return true; } /** * Returns if the current reflection comes from a tokenized source. * * @return boolean */ public function isTokenized() { return true; } /** * Returns the reflection broker used by this reflection object. * * @return \TokenReflection\Broker */ public function getBroker() { return $this->broker; } /** * Returns an element pretty (docblock compatible) name. * * @return string */ public function getPrettyName() { return $this->name . '()'; } /** * Returns the PHP extension reflection. * * @return \TokenReflection\IReflectionExtension|null */ public function getExtension() { return null; } /** * Returns the PHP extension name. * * @return false */ public function getExtensionName() { return false; } /** * Returns the file name the reflection object is defined in. * * @return null */ public function getFileName() { return $this->fileName; } /** * Returns a file reflection. * * @return \TokenReflection\ReflectionFile * @throws \TokenReflection\Exception\RuntimeException If the file is not stored inside the broker */ public function getFileReflection() { throw new Exception\BrokerException($this->getBroker(), sprintf('Function was not parsed from a file', $this->getPrettyName()), Exception\BrokerException::UNSUPPORTED); } /** * Returns the appropriate source code part. * * @return string */ public function getSource() { return ''; } /** * Returns the start position in the file token stream. * * @return integer */ public function getStartPosition() { return -1; } /** * Returns the end position in the file token stream. * * @return integer */ public function getEndPosition() { return -1; } /** * Returns the definition start line number in the file. * * @return integer */ public function getStartLine() { return null; } /** * Returns the definition end line number in the file. * * @return integer */ public function getEndLine() { return null; } /** * Returns the appropriate docblock definition. * * @return boolean */ public function getDocComment() { return false; } /** * Checks if there is a particular annotation. * * @param string $name Annotation name * @return boolean */ public function hasAnnotation($name) { return false; } /** * Returns a particular annotation value. * * @param string $name Annotation name * @return string|array|null */ public function getAnnotation($name) { return null; } /** * Returns all annotations. * * @return array */ public function getAnnotations() { return array(); } /** * Returns if the function/method is a closure. * * @return boolean */ public function isClosure() { return false; } /** * Returns if the function/method is deprecated. * * @return boolean */ public function isDeprecated() { return false; } /** * Returns if the function/method returns its value as reference. * * @return boolean */ public function returnsReference() { return false; } /** * Returns a function/method parameter. * * @param integer|string $parameter Parameter name or position */ public function getParameter($parameter) { if (is_numeric($parameter)) { throw new Exception\RuntimeException(sprintf('There is no parameter at position "%d".', $parameter), Exception\RuntimeException::DOES_NOT_EXIST, $this); } else { throw new Exception\RuntimeException(sprintf('There is no parameter "%s".', $parameter), Exception\RuntimeException::DOES_NOT_EXIST, $this); } } /** * Returns function/method parameters. * * @return array */ public function getParameters(){ return array(); } /** * Returns the number of parameters. * * @return integer */ public function getNumberOfParameters() { return 0; } /** * Returns the number of required parameters. * * @return integer */ public function getNumberOfRequiredParameters() { return 0; } /** * Returns static variables. * * @return array */ public function getStaticVariables() { return array(); } /** * Returns if the method is is disabled via the disable_functions directive. * * @return boolean */ public function isDisabled() { return false; } /** * Calls the function. * * @return mixed */ public function invoke() { return $this->invokeArgs(array()); } /** * Calls the function. * * @param array $args Function parameter values * @return mixed */ public function invokeArgs(array $args) { throw new Exception\RuntimeException('Cannot invoke invalid functions', Exception\RuntimeException::UNSUPPORTED, $this); } /** * Returns imported namespaces and aliases from the declaring namespace. * * @return array */ public function getNamespaceAliases() { return array(); } /** * Returns the function/method as closure. * * @return \Closure */ public function getClosure() { throw new Exception\RuntimeException('Cannot invoke invalid functions', Exception\RuntimeException::UNSUPPORTED, $this); } /** * Returns the closure scope class. * * @return null */ public function getClosureScopeClass() { return null; } /** * Returns this pointer bound to closure. * * @return null */ public function getClosureThis() { return null; } /** * Returns if the function definition is valid. * * @return boolean */ public function isValid() { return false; } /** * Returns the string representation of the reflection object. * * @return string */ public function __toString() { return sprintf( "%sFunction [ function %s%s ] {\n @@ %s %d - %d\n}\n", $this->getDocComment() ? $this->getDocComment() . "\n" : '', $this->returnsReference() ? '&' : '', $this->getName(), $this->getFileName(), $this->getStartLine(), $this->getEndLine() ); } /** * Magic __get method. * * @param string $key Variable name * @return mixed */ final public function __get($key) { return ReflectionBase::get($this, $key); } /** * Magic __isset method. * * @param string $key Variable name * @return boolean */ final public function __isset($key) { return ReflectionBase::exists($this, $key); } } PHP-Token-Reflection-1.4.0/TokenReflection/Php/000077500000000000000000000000001237045466400211465ustar00rootroot00000000000000PHP-Token-Reflection-1.4.0/TokenReflection/Php/IReflection.php000066400000000000000000000014631237045466400240660ustar00rootroot00000000000000broker = $broker; } /** * Returns the PHP extension reflection. * * @return \TokenReflection\Php\ReflectionExtension */ public function getExtension() { return ReflectionExtension::create(parent::getExtension(), $this->broker); } /** * Checks if there is a particular annotation. * * @param string $name Annotation name * @return boolean */ public function hasAnnotation($name) { return false; } /** * Returns a particular annotation value. * * @param string $name Annotation name * @return null */ public function getAnnotation($name) { return null; } /** * Returns parsed docblock. * * @return array */ public function getAnnotations() { return array(); } /** * Returns if the class is an exception or its descendant. * * @return boolean */ public function isException() { return 'Exception' === $this->getName() || $this->isSubclassOf('Exception'); } /** * Returns if objects of this class are cloneable. * * Introduced in PHP 5.4. * * @return boolean * @see http://svn.php.net/viewvc/php/php-src/trunk/ext/reflection/php_reflection.c?revision=307971&view=markup#l4059 */ public function isCloneable() { if ($this->isInterface() || $this->isAbstract()) { return false; } $methods = $this->getMethods(); return isset($methods['__clone']) ? $methods['__clone']->isPublic() : true; } /** * Returns if the current reflection comes from a tokenized source. * * @return boolean */ public function isTokenized() { return false; } /** * Returns if the reflection subject is deprecated. * * @return boolean */ public function isDeprecated() { return false; } /** * Returns if the current class is a subclass of the given class. * * @param string|object $class Class name or reflection object * @return boolean * @throws \TokenReflection\Exception\RuntimeException If an invalid parameter was provided. */ public function isSubclassOf($class) { if (is_object($class)) { if (!$class instanceof InternalReflectionClass && !$class instanceof IReflectionClass) { throw new Exception\RuntimeException('Parameter must be a string or an instance of class reflection.', Exception\RuntimeException::INVALID_ARGUMENT, $this); } $class = $class->getName(); } return in_array($class, $this->getParentClassNameList()); } /** * Returns parent class reflection. * * @return \TokenReflection\Php\ReflectionClass */ public function getParentClass() { $parent = parent::getParentClass(); return $parent ? self::create($parent, $this->broker) : null; } /** * Returns the parent class name. * * @return string */ public function getParentClassName() { $parent = $this->getParentClass(); return $parent ? $parent->getName() : null; } /** * Returns the parent classes reflections. * * @return array */ public function getParentClasses() { $broker = $this->broker; return array_map(function($className) use ($broker) { return $broker->getClass($className); }, $this->getParentClassNameList()); } /** * Returns the parent classes names. * * @return array */ public function getParentClassNameList() { return class_parents($this->getName()); } /** * Returns if the class implements the given interface. * * @param string|object $interface Interface name or reflection object * @return boolean * @throws \TokenReflection\Exception\RuntimeException If the provided parameter is not an interface. */ public function implementsInterface($interface) { if (is_object($interface)) { if (!$interface instanceof InternalReflectionClass && !$interface instanceof IReflectionClass) { throw new Exception\RuntimeException('Parameter must be a string or an instance of class reflection.', Exception\RuntimeException::INVALID_ARGUMENT, $this); } $interfaceName = $interface->getName(); if (!$interface->isInterface()) { throw new Exception\RuntimeException(sprintf('"%s" is not an interface.', $interfaceName), Exception\RuntimeException::INVALID_ARGUMENT, $this); } } else { $reflection = $this->getBroker()->getClass($interface); if (!$reflection->isInterface()) { throw new Exception\RuntimeException(sprintf('"%s" is not an interface.', $interface), Exception\RuntimeException::INVALID_ARGUMENT, $this); } $interfaceName = $interface; } $interfaces = $this->getInterfaces(); return isset($interfaces[$interfaceName]); } /** * Returns an array of interface reflections. * * @return array */ public function getInterfaces() { if (null === $this->interfaces) { $broker = $this->broker; $interfaceNames = $this->getInterfaceNames(); if (empty($interfaceNames)) { $this->interfaces = array(); } else { $this->interfaces = array_combine($interfaceNames, array_map(function($interfaceName) use ($broker) { return $broker->getClass($interfaceName); }, $interfaceNames)); } } return $this->interfaces; } /** * Returns interfaces implemented by this class, not its parents. * * @return array */ public function getOwnInterfaces() { $parent = $this->getParentClass(); return $parent ? array_diff_key($this->getInterfaces(), $parent->getInterfaces()) : $this->getInterfaces(); } /** * Returns names of interfaces implemented by this class, not its parents. * * @return array */ public function getOwnInterfaceNames() { return array_keys($this->getOwnInterfaces()); } /** * Returns class constructor reflection. * * @return \TokenReflection\Php\ReflectionClass|null */ public function getConstructor() { return ReflectionMethod::create(parent::getConstructor(), $this->broker); } /** * Returns class desctructor reflection. * * @return \TokenReflection\Php\ReflectionClass|null */ public function getDestructor() { foreach ($this->getMethods() as $method) { if ($method->isDestructor()) { return $method; } } return null; } /** * Returns a particular method reflection. * * @param string $name Method name * @return \TokenReflection\Php\ReflectionMethod * @throws \TokenReflection\Exception\RuntimeException If the requested method does not exist. */ public function getMethod($name) { foreach ($this->getMethods() as $method) { if ($method->getName() === $name) { return $method; } } throw new Exception\RuntimeException(sprintf('Method %s does not exist.', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this); } /** * Returns class methods. * * @param integer $filter Methods filter * @return array */ public function getMethods($filter = null) { if (null === $this->methods) { $broker = $this->broker; $this->methods = array_map(function(InternalReflectionMethod $method) use ($broker) { return ReflectionMethod::create($method, $broker); }, parent::getMethods()); } if (null === $filter) { return $this->methods; } return array_filter($this->methods, function(ReflectionMethod $method) use ($filter) { return (bool) ($method->getModifiers() & $filter); }); } /** * Returns if the class implements (and not its parents) the given method. * * @param string $name Method name * @return boolean */ public function hasOwnMethod($name) { foreach ($this->getOwnMethods() as $method) { if ($name === $method->getName()) { return true; } } return false; } /** * Returns methods declared by this class, not its parents. * * @param integer $filter * @return array */ public function getOwnMethods($filter = null) { $me = $this->getName(); return array_filter($this->getMethods($filter), function(ReflectionMethod $method) use ($me) { return $method->getDeclaringClass()->getName() === $me; }); } /** * Returns if the class imports the given method from traits. * * @param string $name Method name * @return boolean * @todo Impossible with the current status of reflection */ public function hasTraitMethod($name) { return false; } /** * Returns method reflections imported from traits. * * @param integer $filter Methods filter * @return array * @todo Impossible with the current status of reflection */ public function getTraitMethods($filter = null) { return array(); } /** * Returns a constant reflection. * * @param string $name Constant name * @return \TokenReflection\ReflectionConstant * @throws \TokenReflection\Exception\RuntimeException If the requested constant does not exist. */ public function getConstantReflection($name) { if ($this->hasConstant($name)) { return new ReflectionConstant($name, $this->getConstant($name), $this->broker, $this); } throw new Exception\RuntimeException(sprintf('Constant "%s" does not exist.', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this); } /** * Returns an array of constant reflections. * * @return array */ public function getConstantReflections() { if (null === $this->constants) { $this->constants = array(); foreach ($this->getConstants() as $name => $value) { $this->constants[$name] = $this->getConstantReflection($name); } } return array_values($this->constants); } /** * Returns if the class (and not its parents) defines the given constant. * * @param string $name Constant name. * @return boolean */ public function hasOwnConstant($name) { $constants = $this->getOwnConstants(); return isset($constants[$name]); } /** * Returns constants declared by this class, not its parents. * * @return array */ public function getOwnConstants() { return array_diff_assoc($this->getConstants(), $this->getParentClass() ? $this->getParentClass()->getConstants() : array()); } /** * Returns an array of constant reflections defined by this class and not its parents. * * @return array */ public function getOwnConstantReflections() { $constants = array(); foreach ($this->getOwnConstants() as $name => $value) { $constants[] = $this->getConstantReflection($name); } return $constants; } /** * Returns a particular property reflection. * * @param string $name Property name * @return \TokenReflection\Php\ReflectionProperty * @throws \TokenReflection\Exception\RuntimeException If the requested property does not exist. */ public function getProperty($name) { foreach ($this->getProperties() as $property) { if ($name === $property->getName()) { return $property; } } throw new Exception\RuntimeException(sprintf('Property %s does not exist.', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this); } /** * Returns class properties. * * @param integer $filter Properties filter * @return array */ public function getProperties($filter = null) { if (null === $this->properties) { $broker = $this->broker; $this->properties = array_map(function(InternalReflectionProperty $property) use ($broker) { return ReflectionProperty::create($property, $broker); }, parent::getProperties()); } if (null === $filter) { return $this->properties; } return array_filter($this->properties, function(ReflectionProperty $property) use ($filter) { return (bool) ($property->getModifiers() & $filter); }); } /** * Returns if the class has (and not its parents) the given property. * * @param string $name Property name * @return boolean */ public function hasOwnProperty($name) { foreach ($this->getOwnProperties() as $property) { if ($name === $property->getName()) { return true; } } return false; } /** * Returns properties declared by this class, not its parents. * * @param integer $filter * @return array */ public function getOwnProperties($filter = null) { $me = $this->getName(); return array_filter($this->getProperties($filter), function(ReflectionProperty $property) use ($me) { return $property->getDeclaringClass()->getName() === $me; }); } /** * Returns if the class imports the given property from traits. * * @param string $name Property name * @return boolean * @todo Impossible with the current status of reflection */ public function hasTraitProperty($name) { return false; } /** * Returns property reflections imported from traits. * * @param integer $filter Properties filter * @return array * @todo Impossible with the current status of reflection */ public function getTraitProperties($filter = null) { return array(); } /** * Returns static properties reflections. * * @return array */ public function getStaticProperties() { return $this->getProperties(InternalReflectionProperty::IS_STATIC); } /** * Returns reflections of direct subclasses. * * @return array */ public function getDirectSubclasses() { $that = $this->name; return array_filter($this->getBroker()->getClasses(Broker\Backend::INTERNAL_CLASSES | Broker\Backend::TOKENIZED_CLASSES), function(IReflectionClass $class) use ($that) { if (!$class->isSubclassOf($that)) { return false; } return null === $class->getParentClassName() || !$class->getParentClass()->isSubClassOf($that); }); } /** * Returns names of direct subclasses. * * @return array */ public function getDirectSubclassNames() { return array_keys($this->getDirectSubclasses()); } /** * Returns reflections of indirect subclasses. * * @return array */ public function getIndirectSubclasses() { $that = $this->name; return array_filter($this->getBroker()->getClasses(Broker\Backend::INTERNAL_CLASSES | Broker\Backend::TOKENIZED_CLASSES), function(IReflectionClass $class) use ($that) { if (!$class->isSubclassOf($that)) { return false; } return null !== $class->getParentClassName() && $class->getParentClass()->isSubClassOf($that); }); } /** * Returns names of indirect subclasses. * * @return array */ public function getIndirectSubclassNames() { return array_keys($this->getIndirectSubclasses()); } /** * Returns reflections of classes directly implementing this interface. * * @return array */ public function getDirectImplementers() { if (!$this->isInterface()) { return array(); } $that = $this->name; return array_filter($this->getBroker()->getClasses(Broker\Backend::INTERNAL_CLASSES | Broker\Backend::TOKENIZED_CLASSES), function(IReflectionClass $class) use ($that) { if (!$class->implementsInterface($that)) { return false; } return null === $class->getParentClassName() || !$class->getParentClass()->implementsInterface($that); }); } /** * Returns names of classes directly implementing this interface. * * @return array */ public function getDirectImplementerNames() { return array_keys($this->getDirectImplementers()); } /** * Returns reflections of classes indirectly implementing this interface. * * @return array */ public function getIndirectImplementers() { if (!$this->isInterface()) { return array(); } $that = $this->name; return array_filter($this->getBroker()->getClasses(Broker\Backend::INTERNAL_CLASSES | Broker\Backend::TOKENIZED_CLASSES), function(IReflectionClass $class) use ($that) { if (!$class->implementsInterface($that)) { return false; } return null !== $class->getParentClassName() && $class->getParentClass()->implementsInterface($that); }); } /** * Returns names of classes indirectly implementing this interface. * * @return array */ public function getIndirectImplementerNames() { return array_keys($this->getIndirectImplementers()); } /** * Returns if the class definition is complete. * * Internal classes always have the definition complete. * * @return boolean */ public function isComplete() { return true; } /** * Returns if the class definition is valid. * * Internal classes are always valid. * * @return boolean */ public function isValid() { return true; } /** * Returns imported namespaces and aliases from the declaring namespace. * * @return array */ public function getNamespaceAliases() { return array(); } /** * Returns the reflection broker used by this reflection object. * * @return \TokenReflection\Broker */ public function getBroker() { return $this->broker; } /** * Magic __get method. * * @param string $key Variable name * @return mixed */ final public function __get($key) { return TokenReflection\ReflectionElement::get($this, $key); } /** * Magic __isset method. * * @param string $key Variable name * @return boolean */ final public function __isset($key) { return TokenReflection\ReflectionElement::exists($this, $key); } /** * Returns traits used by this class. * * @return array */ public function getTraits() { return NATIVE_TRAITS ? parent::getTraits() : array(); } /** * Returns traits used by this class and not its parents. * * @return array */ public function getOwnTraits() { if (!NATIVE_TRAITS) { return array(); } $parent = $this->getParentClass(); return $parent ? array_diff_key($this->getTraits(), $parent->getTraits()) : $this->getTraits(); } /** * Returns names of used traits. * * @return array */ public function getTraitNames() { return NATIVE_TRAITS ? parent::getTraitNames() : array(); } /** * Returns traits used by this class and not its parents. * * @return array */ public function getOwnTraitNames() { return array_keys($this->getOwnTraits()); } /** * Returns method aliases from traits. * * @return array */ public function getTraitAliases() { return NATIVE_TRAITS ? parent::getTraitAliases() : array(); } /** * Returns if the class is a trait. * * @return boolean */ public function isTrait() { return NATIVE_TRAITS && parent::isTrait(); } /** * Returns if the class uses a particular trait. * * @param \ReflectionClass|\TokenReflection\IReflectionClass|string $trait Trait reflection or name * @return boolean * @throws \TokenReflection\Exception\RuntimeException If an invalid parameter was provided. */ public function usesTrait($trait) { if (is_object($trait)) { if (!$trait instanceof InternalReflectionClass && !$trait instanceof TokenReflection\IReflectionClass) { throw new Exception\RuntimeException('Parameter must be a string or an instance of trait reflection.', Exception\RuntimeException::INVALID_ARGUMENT, $this); } $traitName = $trait->getName(); if (!$trait->isTrait()) { throw new Exception\RuntimeException(sprintf('"%s" is not a trait.', $traitName), Exception\RuntimeException::INVALID_ARGUMENT, $this); } } else { $reflection = $this->getBroker()->getClass($trait); if (!$reflection->isTrait()) { throw new Exception\RuntimeException(sprintf('"%s" is not a trait.', $trait), Exception\RuntimeException::INVALID_ARGUMENT, $this); } $traitName = $trait; } return in_array($traitName, $this->getTraitNames()); } /** * Creates a new class instance without using a constructor. * * @return object * @throws \TokenReflection\Exception\RuntimeException If the class inherits from an internal class. */ public function newInstanceWithoutConstructor() { if ($this->isInternal()) { throw new Exception\RuntimeException('Could not create an instance; only user defined classes can be instantiated.', Exception\RuntimeException::UNSUPPORTED, $this); } foreach ($this->getParentClasses() as $parent) { if ($parent->isInternal()) { throw new Exception\RuntimeException('Could not create an instance; only user defined classes can be instantiated.', Exception\RuntimeException::UNSUPPORTED, $this); } } if (PHP_VERSION_ID >= 50400) { return parent::newInstanceWithoutConstructor(); } return unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->getName()), $this->getName())); } /** * Returns an element pretty (docblock compatible) name. * * @return string */ public function getPrettyName() { return $this->getName(); } /** * Creates a reflection instance. * * @param \ReflectionClass $internalReflection Internal reflection instance * @param \TokenReflection\Broker $broker Reflection broker instance * @return \TokenReflection\Php\ReflectionClass * @throws \TokenReflection\Exception\RuntimeException If an invalid internal reflection object was provided. */ public static function create(Reflector $internalReflection, Broker $broker) { if (!$internalReflection instanceof InternalReflectionClass) { throw new Exception\RuntimeException('Invalid reflection instance provided, ReflectionClass expected.', Exception\RuntimeException::INVALID_ARGUMENT); } return $broker->getClass($internalReflection->getName()); } } PHP-Token-Reflection-1.4.0/TokenReflection/Php/ReflectionConstant.php000066400000000000000000000227221237045466400254700ustar00rootroot00000000000000name = $name; $this->value = $value; $this->broker = $broker; if (null !== $parent) { $realParent = null; if (array_key_exists($name, $parent->getOwnConstants())) { $realParent = $parent; } if (null === $realParent) { foreach ($parent->getParentClasses() as $grandParent) { if (array_key_exists($name, $grandParent->getOwnConstants())) { $realParent = $grandParent; break; } } } if (null === $realParent) { foreach ($parent->getInterfaces() as $interface) { if (array_key_exists($name, $interface->getOwnConstants())) { $realParent = $interface; break; } } } if (null === $realParent) { throw new Exception\RuntimeException('Could not determine constant real parent class.', Exception\RuntimeException::DOES_NOT_EXIST, $this); } $this->declaringClassName = $realParent->getName(); $this->userDefined = $realParent->isUserDefined(); } else { if (!array_key_exists($name, get_defined_constants(false))) { $this->userDefined = true; } else { $declared = get_defined_constants(true); $this->userDefined = array_key_exists($name, $declared['user']); } } } /** * Returns the name. * * @return string */ public function getName() { return $this->name; } /** * Returns the unqualified name (UQN). * * @return string */ public function getShortName() { $name = $this->getName(); if (null !== $this->namespaceName && $this->namespaceName !== ReflectionNamespace::NO_NAMESPACE_NAME) { $name = substr($name, strlen($this->namespaceName) + 1); } return $name; } /** * Returns the declaring class reflection. * * @return \TokenReflection\IReflectionClass|null */ public function getDeclaringClass() { if (null === $this->declaringClassName) { return null; } return $this->getBroker()->getClass($this->declaringClassName); } /** * Returns the declaring class name. * * @return string|null */ public function getDeclaringClassName() { return $this->declaringClassName; } /** * Returns the namespace name. * * @return string */ public function getNamespaceName() { return $this->namespaceName === TokenReflection\ReflectionNamespace::NO_NAMESPACE_NAME ? '' : $this->namespaceName; } /** * Returns if the function/method is defined within a namespace. * * @return boolean */ public function inNamespace() { return '' !== $this->getNamespaceName(); } /** * Returns the PHP extension reflection. * * @return null */ public function getExtension() { // @todo return null; } /** * Returns the PHP extension name. * * @return boolean */ public function getExtensionName() { return false; } /** * Returns the file name the reflection object is defined in. * * @return null */ public function getFileName() { return null; } /** * Returns the definition start line number in the file. * * @return null */ public function getStartLine() { return null; } /** * Returns the definition end line number in the file. * * @return null */ public function getEndLine() { return null; } /** * Returns the appropriate docblock definition. * * @return boolean */ public function getDocComment() { return false; } /** * Checks if there is a particular annotation. * * @param string $name Annotation name * @return boolean */ public function hasAnnotation($name) { return false; } /** * Returns a particular annotation value. * * @param string $name Annotation name * @return null */ public function getAnnotation($name) { return null; } /** * Returns parsed docblock. * * @return array */ public function getAnnotations() { return array(); } /** * Returns the constant value. * * @return mixed */ public function getValue() { return $this->value; } /** * Returns the part of the source code defining the constant value. * * @return string */ public function getValueDefinition() { return var_export($this->value, true); } /** * Returns the originaly provided value definition. * * @return string */ public function getOriginalValueDefinition() { return token_get_all($this->getValueDefinition()); } /** * Returns if the constant is internal. * * @return boolean */ public function isInternal() { return !$this->userDefined; } /** * Returns if the constant is user defined. * * @return boolean */ public function isUserDefined() { return $this->userDefined; } /** * Returns if the current reflection comes from a tokenized source. * * @return boolean */ public function isTokenized() { return false; } /** * Returns if the reflection subject is deprecated. * * @return boolean */ public function isDeprecated() { return false; } /** * Returns an element pretty (docblock compatible) name. * * @return string */ public function getPrettyName() { return null === $this->declaringClassName ? $this->name : sprintf('%s::%s', $this->declaringClassName, $this->name); } /** * Returns the string representation of the reflection object. * * @return string */ public function __toString() { return sprintf( "Constant [ %s %s ] { %s }\n", gettype($this->getValue()), $this->getName(), $this->getValue() ); } /** * Exports a reflected object. * * @param \TokenReflection\Broker $broker Broker instance * @param string|object|null $class Class name, class instance or null * @param string $constant Constant name * @param boolean $return Return the export instead of outputting it * @return string|null * @throws \TokenReflection\Exception\RuntimeException If requested parameter doesn't exist. */ public static function export(Broker $broker, $class, $constant, $return = false) { $className = is_object($class) ? get_class($class) : $class; $constantName = $constant; if (null === $className) { try { $constant = $broker->getConstant($constantName); } catch (Exception\BrokerException $e) { throw new Exception\RuntimeException(sprintf('Constant %s does not exist.', $constantName), Exception\RuntimeException::DOES_NOT_EXIST); } } else { $class = $broker->getClass($className); if ($class instanceof Invalid\ReflectionClass) { throw new Exception\RuntimeException('Class is invalid.', Exception\RuntimeException::UNSUPPORTED); } elseif ($class instanceof Dummy\ReflectionClass) { throw new Exception\RuntimeException(sprintf('Class %s does not exist.', $className), Exception\RuntimeException::DOES_NOT_EXIST); } $constant = $class->getConstantReflection($constantName); } if ($return) { return $constant->__toString(); } echo $constant->__toString(); } /** * Returns the reflection broker used by this reflection object. * * @return \TokenReflection\Broker */ public function getBroker() { return $this->broker; } /** * Returns imported namespaces and aliases from the declaring namespace. * * @return array */ public function getNamespaceAliases() { return array(); } /** * Returns if the constant definition is valid. * * Internal constants are always valid. * * @return boolean */ public function isValid() { return true; } /** * Magic __get method. * * @param string $key Variable name * @return mixed */ final public function __get($key) { return TokenReflection\ReflectionElement::get($this, $key); } /** * Magic __isset method. * * @param string $key Variable name * @return boolean */ final public function __isset($key) { return TokenReflection\ReflectionElement::exists($this, $key); } /** * Creates a reflection instance. * * Not supported for constants since there is no internal constant reflection. * * @param \ReflectionClass $internalReflection Internal reflection instance * @param \TokenReflection\Broker $broker Reflection broker instance * @return null */ public static function create(Reflector $internalReflection, Broker $broker) { return null; } } PHP-Token-Reflection-1.4.0/TokenReflection/Php/ReflectionExtension.php000066400000000000000000000133001237045466400256430ustar00rootroot00000000000000broker = $broker; } /** * Returns if the constant is internal. * * @return boolean */ public function isInternal() { return true; } /** * Returns if the constant is user defined. * * @return boolean */ public function isUserDefined() { return false; } /** * Returns if the current reflection comes from a tokenized source. * * @return boolean */ public function isTokenized() { return false; } /** * Returns if the reflection subject is deprecated. * * @return boolean */ public function isDeprecated() { return false; } /** * Returns a class reflection. * * @param string $name Class name * @return \TokenReflection\IReflectionClass|null */ public function getClass($name) { $classes = $this->getClasses(); return isset($classes[$name]) ? $classes[$name] : null; } /** * Returns classes defined by this extension. * * @return array */ public function getClasses() { if (null === $this->classes) { $broker = $this->broker; $this->classes = array_map(function($className) use ($broker) { return $broker->getClass($className); }, $this->getClassNames()); } return $this->classes; } /** * Returns a constant value. * * @param string $name Constant name * @return mixed|false */ public function getConstant($name) { $constants = $this->getConstants(); return isset($constants[$name]) ? $constants[$name] : false; } /** * Returns a constant reflection. * * @param string $name Constant name * @return \TokenReflection\IReflectionConstant */ public function getConstantReflection($name) { $constants = $this->getConstantReflections(); return isset($constants[$name]) ? $constants[$name] : null; } /** * Returns reflections of defined constants. * * @return array */ public function getConstantReflections() { if (null === $this->constants) { $broker = $this->broker; $this->constants = array_map(function($constantName) use ($broker) { return $broker->getConstant($constantName); }, array_keys($this->getConstants())); } return $this->constants; } /** * Returns a function reflection. * * @param string $name Function name * @return \TokenReflection\IReflectionFunction */ public function getFunction($name) { $functions = $this->getFunctions(); return isset($functions[$name]) ? $functions[$name] : null; } /** * Returns functions defined by this extension. * * @return array */ public function getFunctions() { if (null === $this->functions) { $broker = $this->broker; $this->classes = array_map(function($functionName) use ($broker) { return $broker->getFunction($functionName); }, array_keys(parent::getFunctions())); } return $this->functions; } /** * Returns names of functions defined by this extension. * * @return array */ public function getFunctionNames() { return array_keys($this->getFunctions()); } /** * Returns an element pretty (docblock compatible) name. * * @return string */ public function getPrettyName() { return $this->getName(); } /** * Returns the reflection broker used by this reflection object. * * @return \TokenReflection\Broker */ public function getBroker() { return $this->broker; } /** * Magic __get method. * * @param string $key Variable name * @return mixed */ final public function __get($key) { return TokenReflection\ReflectionElement::get($this, $key); } /** * Magic __isset method. * * @param string $key Variable name * @return boolean */ final public function __isset($key) { return TokenReflection\ReflectionElement::exists($this, $key); } /** * Creates a reflection instance. * * @param \ReflectionClass $internalReflection Internal reflection instance * @param \TokenReflection\Broker $broker Reflection broker instance * @return \TokenReflection\Php\ReflectionExtension * @throws \TokenReflection\Exception\RuntimeException If an invalid internal reflection object was provided. */ public static function create(Reflector $internalReflection, Broker $broker) { static $cache = array(); if (!$internalReflection instanceof InternalReflectionExtension) { throw new Exception\RuntimeException('Invalid reflection instance provided, ReflectionExtension expected.', Exception\RuntimeException::INVALID_ARGUMENT); } if (!isset($cache[$internalReflection->getName()])) { $cache[$internalReflection->getName()] = new self($internalReflection->getName(), $broker); } return $cache[$internalReflection->getName()]; } } PHP-Token-Reflection-1.4.0/TokenReflection/Php/ReflectionFunction.php000066400000000000000000000135521237045466400254650ustar00rootroot00000000000000broker = $broker; } /** * Returns the PHP extension reflection. * * @return \TokenReflection\IReflectionExtension */ public function getExtension() { return ReflectionExtension::create(parent::getExtension(), $this->broker); } /** * Checks if there is a particular annotation. * * @param string $name Annotation name * @return boolean */ public function hasAnnotation($name) { return false; } /** * Returns a particular annotation value. * * @param string $name Annotation name * @return null */ public function getAnnotation($name) { return null; } /** * Returns parsed docblock. * * @return array */ public function getAnnotations() { return array(); } /** * Returns if the current reflection comes from a tokenized source. * * @return boolean */ public function isTokenized() { return false; } /** * Returns a particular parameter. * * @param integer|string $parameter Parameter name or position * @return \TokenReflection\Php\ReflectionParameter * @throws \TokenReflection\Exception\RuntimeException If there is no parameter of the given name. * @throws \TokenReflection\Exception\RuntimeException If there is no parameter at the given position. */ public function getParameter($parameter) { $parameters = $this->getParameters(); if (is_numeric($parameter)) { if (!isset($parameters[$parameter])) { throw new Exception\RuntimeException(sprintf('There is no parameter at position "%d".', $parameter), Exception\RuntimeException::DOES_NOT_EXIST, $this); } return $parameters[$parameter]; } else { foreach ($parameters as $reflection) { if ($reflection->getName() === $parameter) { return $reflection; } } throw new Exception\RuntimeException(sprintf('There is no parameter "%s".', $parameter), Exception\RuntimeException::DOES_NOT_EXIST, $this); } } /** * Returns function parameters. * * @return array */ public function getParameters() { if (null === $this->parameters) { $broker = $this->broker; $parent = $this; $this->parameters = array_map(function(InternalReflectionParameter $parameter) use ($broker, $parent) { return ReflectionParameter::create($parameter, $broker, $parent); }, parent::getParameters()); } return $this->parameters; } /** * Returns the reflection broker used by this reflection object. * * @return \TokenReflection\Broker */ public function getBroker() { return $this->broker; } /** * Returns imported namespaces and aliases from the declaring namespace. * * @return array */ public function getNamespaceAliases() { return array(); } /** * Magic __get method. * * @param string $key Variable name * @return mixed */ final public function __get($key) { return TokenReflection\ReflectionElement::get($this, $key); } /** * Magic __isset method. * * @param string $key Variable name * @return boolean */ final public function __isset($key) { return TokenReflection\ReflectionElement::exists($this, $key); } /** * Returns the function/method as closure. * * @return \Closure */ public function getClosure() { if (PHP_VERSION_ID >= 50400) { return parent::getClosure(); } else { $that = $this; return function() use ($that) { return $that->invokeArgs(func_get_args()); }; } } /** * Returns the closure scope class. * * @return string|null */ public function getClosureScopeClass() { return PHP_VERSION_ID >= 50400 ? parent::getClosureScopeClass() : null; } /** * Returns this pointer bound to closure. * * @return null */ public function getClosureThis() { return PHP_VERSION_ID >= 50400 ? parent::getClosureThis() : null; } /** * Returns if the function definition is valid. * * Internal functions are always valid. * * @return boolean */ public function isValid() { return true; } /** * Returns an element pretty (docblock compatible) name. * * @return string */ public function getPrettyName() { return $this->getName() . '()'; } /** * Creates a reflection instance. * * @param \ReflectionClass $internalReflection Internal reflection instance * @param \TokenReflection\Broker $broker Reflection broker instance * @return \TokenReflection\Php\ReflectionFunction * @throws \TokenReflection\Exception\RuntimeException If an invalid internal reflection object was provided. */ public static function create(Reflector $internalReflection, Broker $broker) { if (!$internalReflection instanceof InternalReflectionFunction) { throw new Exception\RuntimeException('Invalid reflection instance provided, ReflectionFunction expected.', Exception\RuntimeException::INVALID_ARGUMENT); } return $broker->getFunction($internalReflection->getName()); } }PHP-Token-Reflection-1.4.0/TokenReflection/Php/ReflectionMethod.php000066400000000000000000000205501237045466400251140ustar00rootroot00000000000000broker = $broker; } /** * Returns the declaring class reflection. * * @return \TokenReflection\IReflectionClass */ public function getDeclaringClass() { return ReflectionClass::create(parent::getDeclaringClass(), $this->broker); } /** * Returns the declaring class name. * * @return string */ public function getDeclaringClassName() { return $this->getDeclaringClass()->getName(); } /** * Returns imported namespaces and aliases from the declaring namespace. * * @return array */ public function getNamespaceAliases() { return $this->getDeclaringClass()->getNamespaceAliases(); } /** * Checks if there is a particular annotation. * * @param string $name Annotation name * @return boolean */ public function hasAnnotation($name) { return false; } /** * Returns a particular annotation value. * * @param string $name Annotation name * @return null */ public function getAnnotation($name) { return null; } /** * Returns parsed docblock. * * @return array */ public function getAnnotations() { return array(); } /** * Returns if the current reflection comes from a tokenized source. * * @return boolean */ public function isTokenized() { return false; } /** * Returns the method prototype. * * @return \TokenReflection\Php\ReflectionMethod */ public function getPrototype() { return self::create(parent::getPrototype(), $this->broker); } /** * Returns a particular parameter. * * @param integer|string $parameter Parameter name or position * @return \TokenReflection\Php\ReflectionParameter * @throws \TokenReflection\Exception\RuntimeException If there is no parameter of the given name. * @throws \TokenReflection\Exception\RuntimeException If there is no parameter at the given position. */ public function getParameter($parameter) { $parameters = $this->getParameters(); if (is_numeric($parameter)) { if (!isset($parameters[$parameter])) { throw new Exception\RuntimeException(sprintf('There is no parameter at position "%d".', $parameter), Exception\RuntimeException::DOES_NOT_EXIST, $this); } return $parameters[$parameter]; } else { foreach ($parameters as $reflection) { if ($reflection->getName() === $parameter) { return $reflection; } } throw new Exception\RuntimeException(sprintf('There is no parameter "%s".', $parameter), Exception\RuntimeException::DOES_NOT_EXIST, $this); } } /** * Returns function parameters. * * @return array */ public function getParameters() { if (null === $this->parameters) { $broker = $this->broker; $parent = $this; $this->parameters = array_map(function(InternalReflectionParameter $parameter) use ($broker, $parent) { return ReflectionParameter::create($parameter, $broker, $parent); }, parent::getParameters()); } return $this->parameters; } /** * Returns if the method is set accessible. * * @return boolean */ public function isAccessible() { return $this->accessible; } /** * Sets a method to be accessible or not. * * Introduced in PHP 5.3.2. Throws an exception if run on an older version. * * @param boolean $accessible * @throws \TokenReflection\Exception\RuntimeException If run on PHP version < 5.3.2. */ public function setAccessible($accessible) { if (PHP_VERSION_ID < 50302) { throw new Exception\RuntimeException(sprintf('Method setAccessible was introduced the internal reflection in PHP 5.3.2, you are using %s.', PHP_VERSION), Exception\RuntimeException::UNSUPPORTED, $this); } $this->accessible = $accessible; parent::setAccessible($accessible); } /** * Shortcut for isPublic(), ... methods that allows or-ed modifiers. * * @param integer $filter Filter * @return boolean */ public function is($filter = null) { return null === $filter || ($this->getModifiers() & $filter); } /** * Returns the reflection broker used by this reflection object. * * @return \TokenReflection\Broker */ public function getBroker() { return $this->broker; } /** * Magic __get method. * * @param string $key Variable name * @return mixed */ final public function __get($key) { return TokenReflection\ReflectionElement::get($this, $key); } /** * Magic __isset method. * * @param string $key Variable name * @return boolean */ final public function __isset($key) { return TokenReflection\ReflectionElement::exists($this, $key); } /** * Returns the function/method as closure. * * @param object $object Object * @return \Closure */ public function getClosure($object) { if (PHP_VERSION_ID >= 50400) { return parent::getClosure(); } else { $that = $this; return function() use ($object, $that) { return $that->invokeArgs($object, func_get_args()); }; } } /** * Returns the closure scope class. * * @return string|null */ public function getClosureScopeClass() { return PHP_VERSION_ID >= 50400 ? parent::getClosureScopeClass() : null; } /** * Returns this pointer bound to closure. * * @return null */ public function getClosureThis() { return PHP_VERSION_ID >= 50400 ? parent::getClosureThis() : null; } /** * Returns the original name when importing from a trait. * * @return string */ public function getOriginalName() { return null; } /** * Returns the original method when importing from a trait. * * @return null */ public function getOriginal() { return null; } /** * Returns the original modifiers value when importing from a trait. * * @return null */ public function getOriginalModifiers() { return null; } /** * Returns the defining trait. * * @return \TokenReflection\IReflectionClass|null */ public function getDeclaringTrait() { return null; } /** * Returns the declaring trait name. * * @return string|null */ public function getDeclaringTraitName() { return null; } /** * Returns an element pretty (docblock compatible) name. * * @return string */ public function getPrettyName() { return sprintf('%s::%s()', $this->getDeclaringClassName(), $this->getName()); } /** * Creates a reflection instance. * * @param \ReflectionClass $internalReflection Internal reflection instance * @param \TokenReflection\Broker $broker Reflection broker instance * @return \TokenReflection\Php\IReflection * @throws \TokenReflection\Exception\RuntimeException If an invalid internal reflection object was provided. */ public static function create(Reflector $internalReflection, Broker $broker) { static $cache = array(); if (!$internalReflection instanceof InternalReflectionMethod) { throw new Exception\RuntimeException('Invalid reflection instance provided, ReflectionMethod expected.', Exception\RuntimeException::INVALID_ARGUMENT); } $key = $internalReflection->getDeclaringClass()->getName() . '::' . $internalReflection->getName(); if (!isset($cache[$key])) { $cache[$key] = new self($internalReflection->getDeclaringClass()->getName(), $internalReflection->getName(), $broker); } return $cache[$key]; } } PHP-Token-Reflection-1.4.0/TokenReflection/Php/ReflectionParameter.php000066400000000000000000000206321237045466400256150ustar00rootroot00000000000000broker = $broker; $this->userDefined = $parent->isUserDefined(); } /** * Returns the declaring class reflection. * * @return \TokenReflection\IReflectionClass */ public function getDeclaringClass() { $class = parent::getDeclaringClass(); return $class ? ReflectionClass::create($class, $this->broker) : null; } /** * Returns the declaring class name. * * @return string|null */ public function getDeclaringClassName() { $class = parent::getDeclaringClass(); return $class ? $class->getName() : null; } /** * Returns imported namespaces and aliases from the declaring namespace. * * @return array */ public function getNamespaceAliases() { return $this->getDeclaringFunction()->getNamespaceAliases(); } /** * Returns the file name the reflection object is defined in. * * @return string */ public function getFileName() { return $this->getDeclaringFunction()->getFileName(); } /** * Returns the PHP extension reflection. * * @return \TokenReflection\Php\ReflectionExtension */ public function getExtension() { return $this->getDeclaringFunction()->getExtension(); } /** * Returns the PHP extension name. * * @return string|boolean */ public function getExtensionName() { $extension = $this->getExtension(); return $extension ? $extension->getName() : false; } /** * Checks if there is a particular annotation. * * @param string $name Annotation name * @return boolean */ public function hasAnnotation($name) { return false; } /** * Returns a particular annotation value. * * @param string $name Annotation name * @return null */ public function getAnnotation($name) { return null; } /** * Returns parsed docblock. * * @return array */ public function getAnnotations() { return array(); } /** * Returns the declaring function reflection. * * @return \TokenReflection\Php\ReflectionFunction|\TokenReflection\Php\ReflectionMethod */ public function getDeclaringFunction() { $class = $this->getDeclaringClass(); $function = parent::getDeclaringFunction(); return $class ? $class->getMethod($function->getName()) : ReflectionFunction::create($function, $this->broker); } /** * Returns the declaring function name. * * @return string|null */ public function getDeclaringFunctionName() { $function = parent::getDeclaringFunction(); return $function ? $function->getName() : $function; } /** * Returns the definition start line number in the file. * * @return null */ public function getStartLine() { return null; } /** * Returns the definition end line number in the file. * * @return null */ public function getEndLine() { return null; } /** * Returns the appropriate docblock definition. * * @return boolean */ public function getDocComment() { return false; } /** * Returns the part of the source code defining the paramter default value. * * @return string|null */ public function getDefaultValueDefinition() { $value = $this->getDefaultValue(); return null === $value ? null : var_export($value, true); } /** * Returns if the default value is defined by a constant. * * @return boolean */ public function isDefaultValueConstant() { return PHP_VERSION_ID >= 50406 && parent::isDefaultValueAvailable(); } /** * Returns the name of the default value constant. * * @return string|null */ public function getDefaultValueConstantName() { if (!$this->isOptional()) { throw new Exception\RuntimeException('Property is not optional.', Exception\RuntimeException::UNSUPPORTED, $this); } return $this->isDefaultValueConstant() ? parent::getDefaultValueConstantName : null; } /** * Returns if the parameter expects a callback. * * @return boolean */ public function isCallable() { return PHP_VERSION_ID >= 50400 && parent::isCallable(); } /** * Returns the original type hint as defined in the source code. * * @return string|null */ public function getOriginalTypeHint() { return !$this->isArray() && !$this->isCallable() ? $this->getClass() : null; } /** * Returns the required class name of the value. * * @return string|null */ public function getClassName() { return $this->getClass() ? $this->getClass()->getName() : null; } /** * Returns if the parameter is internal. * * @return boolean */ public function isInternal() { return !$this->userDefined; } /** * Returns if the parameter is user defined. * * @return boolean */ public function isUserDefined() { return $this->userDefined; } /** * Returns if the current reflection comes from a tokenized source. * * @return boolean */ public function isTokenized() { return false; } /** * Returns if the reflection subject is deprecated. * * @return boolean */ public function isDeprecated() { return false; } /** * Returns the reflection broker used by this reflection object. * * @return \TokenReflection\Broker */ public function getBroker() { return $this->broker; } /** * Returns if the paramter value can be passed by value. * * @return boolean */ public function canBePassedByValue() { return method_exists($this, 'canBePassedByValue') ? parent::canBePassedByValue() : !$this->isPassedByReference(); } /** * Returns an element pretty (docblock compatible) name. * * @return string */ public function getPrettyName() { return str_replace('()', '($' . $this->getName() . ')', $this->getDeclaringFunction()->getPrettyName()); } /** * Magic __get method. * * @param string $key Variable name * @return mixed */ final public function __get($key) { return TokenReflection\ReflectionElement::get($this, $key); } /** * Magic __isset method. * * @param string $key Variable name * @return boolean */ final public function __isset($key) { return TokenReflection\ReflectionElement::exists($this, $key); } /** * Creates a reflection instance. * * @param \ReflectionClass $internalReflection Internal reflection instance * @param \TokenReflection\Broker $broker Reflection broker instance * @return \TokenReflection\Php\ReflectionParameter * @throws \TokenReflection\Exception\RuntimeException If an invalid internal reflection object was provided. */ public static function create(Reflector $internalReflection, Broker $broker) { static $cache = array(); if (!$internalReflection instanceof InternalReflectionParameter) { throw new Exception\RuntimeException('Invalid reflection instance provided, ReflectionParameter expected.', Exception\RuntimeException::INVALID_ARGUMENT); } $class = $internalReflection->getDeclaringClass(); $function = $internalReflection->getDeclaringFunction(); $key = $class ? $class->getName() . '::' : ''; $key .= $function->getName() . '(' . $internalReflection->getName() . ')'; if (!isset($cache[$key])) { $cache[$key] = new self($class ? array($class->getName(), $function->getName()) : $function->getName(), $internalReflection->getName(), $broker, $function); } return $cache[$key]; } } PHP-Token-Reflection-1.4.0/TokenReflection/Php/ReflectionProperty.php000066400000000000000000000154051237045466400255230ustar00rootroot00000000000000broker = $broker; } /** * Returns the declaring class reflection. * * @return \TokenReflection\IReflectionClass */ public function getDeclaringClass() { return ReflectionClass::create(parent::getDeclaringClass(), $this->broker); } /** * Returns the declaring class name. * * @return string */ public function getDeclaringClassName() { return $this->getDeclaringClass()->getName(); } /** * Returns the definition start line number in the file. * * @return null */ public function getStartLine() { return null; } /** * Returns the definition end line number in the file. * * @return null */ public function getEndLine() { return null; } /** * Returns the appropriate docblock definition. * * @return boolean */ public function getDocComment() { return false; } /** * Checks if there is a particular annotation. * * @param string $name Annotation name * @return boolean */ public function hasAnnotation($name) { return false; } /** * Returns a particular annotation value. * * @param string $name Annotation name * @return null */ public function getAnnotation($name) { return null; } /** * Returns parsed docblock. * * @return array */ public function getAnnotations() { return array(); } /** * Returns the property default value. * * @return mixed */ public function getDefaultValue() { $values = $this->getDeclaringClass()->getDefaultProperties(); return $values[$this->getName()]; } /** * Returns the part of the source code defining the property default value. * * @return string */ public function getDefaultValueDefinition() { $value = $this->getDefaultValue(); return null === $value ? null : var_export($value, true); } /** * Returns if the property is internal. * * @return boolean */ public function isInternal() { return $this->getDeclaringClass()->isInternal(); } /** * Returns if the property is user defined. * * @return boolean */ public function isUserDefined() { return $this->getDeclaringClass()->isUserDefined(); } /** * Returns if the current reflection comes from a tokenized source. * * @return boolean */ public function isTokenized() { return false; } /** * Returns if the reflection subject is deprecated. * * @return boolean */ public function isDeprecated() { return false; } /** * Returns the reflection broker used by this reflection object. * * @return \TokenReflection\Broker */ public function getBroker() { return $this->broker; } /** * Returns imported namespaces and aliases from the declaring namespace. * * @return array */ public function getNamespaceAliases() { return array(); } /** * Returns the defining trait. * * @return \TokenReflection\IReflectionClass|null */ public function getDeclaringTrait() { return null; } /** * Returns the declaring trait name. * * @return string|null */ public function getDeclaringTraitName() { return null; } /** * Returns if the property is set accessible. * * @return boolean */ public function isAccessible() { return $this->accessible; } /** * Sets a property to be accessible or not. * * @param boolean $accessible If the property should be accessible. */ public function setAccessible($accessible) { $this->accessible = (bool) $accessible; parent::setAccessible($accessible); } /** * Returns the PHP extension reflection. * * @return \TokenReflection\Php\ReflectionExtension */ public function getExtension() { return $this->getDeclaringClass()->getExtension(); } /** * Returns the PHP extension name. * * @return string|boolean */ public function getExtensionName() { $extension = $this->getExtension(); return $extension ? $extension->getName() : false; } /** * Returns the file name the reflection object is defined in. * * @return string */ public function getFileName() { return $this->getDeclaringClass()->getFileName(); } /** * Returns an element pretty (docblock compatible) name. * * @return string */ public function getPrettyName() { return sprintf('%s::$%s', $this->getDeclaringClassName(), $this->getName()); } /** * Magic __get method. * * @param string $key Variable name * @return mixed */ final public function __get($key) { return TokenReflection\ReflectionElement::get($this, $key); } /** * Magic __isset method. * * @param string $key Variable name * @return boolean */ final public function __isset($key) { return TokenReflection\ReflectionElement::exists($this, $key); } /** * Creates a reflection instance. * * @param \ReflectionClass $internalReflection Internal reflection instance * @param \TokenReflection\Broker $broker Reflection broker instance * @return \TokenReflection\Php\ReflectionProperty * @throws \TokenReflection\Exception\RuntimeException If an invalid internal reflection object was provided. */ public static function create(Reflector $internalReflection, Broker $broker) { static $cache = array(); if (!$internalReflection instanceof InternalReflectionProperty) { throw new Exception\RuntimeException('Invalid reflection instance provided, ReflectionProperty expected.', Exception\RuntimeException::INVALID_ARGUMENT); } $key = $internalReflection->getDeclaringClass()->getName() . '::' . $internalReflection->getName(); if (!isset($cache[$key])) { $cache[$key] = new self($internalReflection->getDeclaringClass()->getName(), $internalReflection->getName(), $broker); } return $cache[$key]; } } PHP-Token-Reflection-1.4.0/TokenReflection/ReflectionAnnotation.php000066400000000000000000000325341237045466400252640ustar00rootroot00000000000000reflection = $reflection; $this->docComment = $docComment ?: false; } /** * Returns the docblock. * * @return string|boolean */ public function getDocComment() { return $this->docComment; } /** * Returns if the current docblock contains the requrested annotation. * * @param string $annotation Annotation name * @return boolean */ public function hasAnnotation($annotation) { if (null === $this->annotations) { $this->parse(); } return isset($this->annotations[$annotation]); } /** * Returns a particular annotation value. * * @param string $annotation Annotation name * @return string|array|null */ public function getAnnotation($annotation) { if (null === $this->annotations) { $this->parse(); } return isset($this->annotations[$annotation]) ? $this->annotations[$annotation] : null; } /** * Returns all parsed annotations. * * @return array */ public function getAnnotations() { if (null === $this->annotations) { $this->parse(); } return $this->annotations; } /** * Sets Docblock templates. * * @param array $templates Docblock templates * @return \TokenReflection\ReflectionAnnotation * @throws \TokenReflection\Exception\RuntimeException If an invalid annotation template was provided. */ public function setTemplates(array $templates) { foreach ($templates as $template) { if (!$template instanceof ReflectionAnnotation) { throw new Exception\RuntimeException( sprintf( 'All templates have to be instances of \\TokenReflection\\ReflectionAnnotation; %s given.', is_object($template) ? get_class($template) : gettype($template) ), Exception\RuntimeException::INVALID_ARGUMENT, $this->reflection ); } } $this->templates = $templates; return $this; } /** * Parses reflection object documentation. */ private function parse() { $this->annotations = array(); if (false !== $this->docComment) { // Parse docblock $name = self::SHORT_DESCRIPTION; $docblock = trim( preg_replace( array( '~^' . preg_quote(ReflectionElement::DOCBLOCK_TEMPLATE_START, '~') . '~', '~^' . preg_quote(ReflectionElement::DOCBLOCK_TEMPLATE_END, '~') . '$~', '~^/\\*\\*~', '~\\*/$~' ), '', $this->docComment ) ); foreach (explode("\n", $docblock) as $line) { $line = preg_replace('~^\\*\\s?~', '', trim($line)); // End of short description if ('' === $line && self::SHORT_DESCRIPTION === $name) { $name = self::LONG_DESCRIPTION; continue; } // @annotation if (preg_match('~^\\s*@([\\S]+)\\s*(.*)~', $line, $matches)) { $name = $matches[1]; $this->annotations[$name][] = $matches[2]; continue; } // Continuation if (self::SHORT_DESCRIPTION === $name || self::LONG_DESCRIPTION === $name) { if (!isset($this->annotations[$name])) { $this->annotations[$name] = $line; } else { $this->annotations[$name] .= "\n" . $line; } } else { $this->annotations[$name][count($this->annotations[$name]) - 1] .= "\n" . $line; } } array_walk_recursive($this->annotations, function(&$value) { // {@*} is a placeholder for */ (phpDocumentor compatibility) $value = str_replace('{@*}', '*/', $value); $value = trim($value); }); } if ($this->reflection instanceof ReflectionElement) { // Merge docblock templates $this->mergeTemplates(); // Copy annotations if the @copydoc tag is present. if (!empty($this->annotations['copydoc'])) { $this->copyAnnotation(); } // Process docblock inheritance for supported reflections if ($this->reflection instanceof ReflectionClass || $this->reflection instanceof ReflectionMethod || $this->reflection instanceof ReflectionProperty) { $this->inheritAnnotations(); } } } /** * Copies annotations if the @copydoc tag is present. * * @throws \TokenReflection\Exception\RuntimeException When stuck in an infinite loop when resolving the @copydoc tag. */ private function copyAnnotation() { self::$copydocStack[] = $this->reflection; $broker = $this->reflection->getBroker(); $parentNames = $this->annotations['copydoc']; unset($this->annotations['copydoc']); foreach ($parentNames as $parentName) { try { if ($this->reflection instanceof ReflectionClass) { $parent = $broker->getClass($parentName); if ($parent instanceof Dummy\ReflectionClass) { // The class to copy from is not usable return; } } elseif ($this->reflection instanceof ReflectionFunction) { $parent = $broker->getFunction(rtrim($parentName, '()')); } elseif ($this->reflection instanceof ReflectionConstant && null === $this->reflection->getDeclaringClassName()) { $parent = $broker->getConstant($parentName); } elseif ($this->reflection instanceof ReflectionMethod || $this->reflection instanceof ReflectionProperty || $this->reflection instanceof ReflectionConstant) { if (false !== strpos($parentName, '::')) { list($className, $parentName) = explode('::', $parentName, 2); $class = $broker->getClass($className); } else { $class = $this->reflection->getDeclaringClass(); } if ($class instanceof Dummy\ReflectionClass) { // The source element class is not usable return; } if ($this->reflection instanceof ReflectionMethod) { $parent = $class->getMethod(rtrim($parentName, '()')); } elseif ($this->reflection instanceof ReflectionConstant) { $parent = $class->getConstantReflection($parentName); } else { $parent = $class->getProperty(ltrim($parentName, '$')); } } if (!empty($parent)) { // Don't get into an infinite recursion loop if (in_array($parent, self::$copydocStack, true)) { throw new Exception\RuntimeException('Infinite loop detected when copying annotations using the @copydoc tag.', Exception\RuntimeException::INVALID_ARGUMENT, $this->reflection); } self::$copydocStack[] = $parent; // We can get into an infinite loop here (e.g. when two methods @copydoc from each other) foreach ($parent->getAnnotations() as $name => $value) { // Add annotations that are not already present if (empty($this->annotations[$name])) { $this->annotations[$name] = $value; } } array_pop(self::$copydocStack); } } catch (Exception\BaseException $e) { // Ignoring links to non existent elements, ... } } array_pop(self::$copydocStack); } /** * Merges templates with the current docblock. */ private function mergeTemplates() { foreach ($this->templates as $index => $template) { if (0 === $index && $template->getDocComment() === $this->docComment) { continue; } foreach ($template->getAnnotations() as $name => $value) { if ($name === self::LONG_DESCRIPTION) { // Long description if (isset($this->annotations[self::LONG_DESCRIPTION])) { $this->annotations[self::LONG_DESCRIPTION] = $value . "\n" . $this->annotations[self::LONG_DESCRIPTION]; } else { $this->annotations[self::LONG_DESCRIPTION] = $value; } } elseif ($name !== self::SHORT_DESCRIPTION) { // Tags; short description is not inherited if (isset($this->annotations[$name])) { $this->annotations[$name] = array_merge($this->annotations[$name], $value); } else { $this->annotations[$name] = $value; } } } } } /** * Inherits annotations from parent classes/methods/properties if needed. * * @throws \TokenReflection\Exception\RuntimeException If unsupported reflection was used. */ private function inheritAnnotations() { if ($this->reflection instanceof ReflectionClass) { $declaringClass = $this->reflection; } elseif ($this->reflection instanceof ReflectionMethod || $this->reflection instanceof ReflectionProperty) { $declaringClass = $this->reflection->getDeclaringClass(); } $parents = array_filter(array_merge(array($declaringClass->getParentClass()), $declaringClass->getOwnInterfaces()), function($class) { return $class instanceof ReflectionClass; }); // In case of properties and methods, look for a property/method of the same name and return // and array of such members. $parentDefinitions = array(); if ($this->reflection instanceof ReflectionProperty) { $name = $this->reflection->getName(); foreach ($parents as $parent) { if ($parent->hasProperty($name)) { $parentDefinitions[] = $parent->getProperty($name); } } $parents = $parentDefinitions; } elseif ($this->reflection instanceof ReflectionMethod) { $name = $this->reflection->getName(); foreach ($parents as $parent) { if ($parent->hasMethod($name)) { $parentDefinitions[] = $parent->getMethod($name); } } $parents = $parentDefinitions; } if (false === $this->docComment) { // Inherit the entire docblock foreach ($parents as $parent) { $annotations = $parent->getAnnotations(); if (!empty($annotations)) { $this->annotations = $annotations; break; } } } else { if (isset($this->annotations[self::LONG_DESCRIPTION]) && false !== stripos($this->annotations[self::LONG_DESCRIPTION], '{@inheritdoc}')) { // Inherit long description foreach ($parents as $parent) { if ($parent->hasAnnotation(self::LONG_DESCRIPTION)) { $this->annotations[self::LONG_DESCRIPTION] = str_ireplace( '{@inheritdoc}', $parent->getAnnotation(self::LONG_DESCRIPTION), $this->annotations[self::LONG_DESCRIPTION] ); break; } } $this->annotations[self::LONG_DESCRIPTION] = str_ireplace('{@inheritdoc}', '', $this->annotations[self::LONG_DESCRIPTION]); } if (isset($this->annotations[self::SHORT_DESCRIPTION]) && false !== stripos($this->annotations[self::SHORT_DESCRIPTION], '{@inheritdoc}')) { // Inherit short description foreach ($parents as $parent) { if ($parent->hasAnnotation(self::SHORT_DESCRIPTION)) { $this->annotations[self::SHORT_DESCRIPTION] = str_ireplace( '{@inheritdoc}', $parent->getAnnotation(self::SHORT_DESCRIPTION), $this->annotations[self::SHORT_DESCRIPTION] ); break; } } $this->annotations[self::SHORT_DESCRIPTION] = str_ireplace('{@inheritdoc}', '', $this->annotations[self::SHORT_DESCRIPTION]); } } // In case of properties check if we need and can inherit the data type if ($this->reflection instanceof ReflectionProperty && empty($this->annotations['var'])) { foreach ($parents as $parent) { if ($parent->hasAnnotation('var')) { $this->annotations['var'] = $parent->getAnnotation('var'); break; } } } if ($this->reflection instanceof ReflectionMethod) { if (0 !== $this->reflection->getNumberOfParameters() && (empty($this->annotations['param']) || count($this->annotations['param']) < $this->reflection->getNumberOfParameters())) { // In case of methods check if we need and can inherit parameter descriptions $params = isset($this->annotations['param']) ? $this->annotations['param'] : array(); $complete = false; foreach ($parents as $parent) { if ($parent->hasAnnotation('param')) { $parentParams = array_slice($parent->getAnnotation('param'), count($params)); while (!empty($parentParams) && !$complete) { array_push($params, array_shift($parentParams)); if (count($params) === $this->reflection->getNumberOfParameters()) { $complete = true; } } } if ($complete) { break; } } if (!empty($params)) { $this->annotations['param'] = $params; } } // And check if we need and can inherit the return and throws value foreach (array('return', 'throws') as $paramName) { if (!isset($this->annotations[$paramName])) { foreach ($parents as $parent) { if ($parent->hasAnnotation($paramName)) { $this->annotations[$paramName] = $parent->getAnnotation($paramName); break; } } } } } } } PHP-Token-Reflection-1.4.0/TokenReflection/ReflectionBase.php000066400000000000000000000123511237045466400240170ustar00rootroot00000000000000broker = $broker; $this->parseStream($tokenStream, $parent); } /** * Parses the token substream. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @param \TokenReflection\IReflection $parent Parent reflection object */ abstract protected function parseStream(Stream $tokenStream, IReflection $parent = null); /** * Returns the name (FQN). * * @return string */ public function getName() { return $this->name; } /** * Returns the appropriate docblock definition. * * @return string|boolean */ public function getDocComment() { return $this->docComment->getDocComment(); } /** * Checks if there is a particular annotation. * * @param string $name Annotation name * @return boolean */ final public function hasAnnotation($name) { return $this->docComment->hasAnnotation($name); } /** * Returns a particular annotation value. * * @param string $name Annotation name * @return string|array|null */ final public function getAnnotation($name) { return $this->docComment->getAnnotation($name); } /** * Returns all annotations. * * @return array */ final public function getAnnotations() { return $this->docComment->getAnnotations(); } /** * Returns the reflection broker used by this reflection object. * * @return \TokenReflection\Broker */ public function getBroker() { return $this->broker; } /** * Returns if the reflection object is internal. * * Always returns false - everything is user defined. * * @return boolean */ public function isInternal() { return false; } /** * Returns if the reflection object is user defined. * * Always returns true - everything is user defined. * * @return boolean */ public function isUserDefined() { return true; } /** * Returns if the current reflection comes from a tokenized source. * * @return boolean */ public function isTokenized() { return true; } /** * Returns if the reflection subject is deprecated. * * @return boolean */ public function isDeprecated() { return $this->hasAnnotation('deprecated'); } /** * Returns the appropriate source code part. * * @return string */ abstract public function getSource(); /** * Returns an element pretty (docblock compatible) name. * * @return string */ public function getPrettyName() { return $this->name; } /** * Magic __get method. * * @param string $key Variable name * @return mixed */ final public function __get($key) { return self::get($this, $key); } /** * Magic __isset method. * * @param string $key Variable name * @return boolean */ final public function __isset($key) { return self::exists($this, $key); } /** * Magic __get method helper. * * @param \TokenReflection\IReflection $object Reflection object * @param string $key Variable name * @return mixed * @throws \TokenReflection\Exception\RuntimeException If the requested parameter does not exist. */ final public static function get(IReflection $object, $key) { if (!empty($key)) { $className = get_class($object); if (!isset(self::$methodCache[$className])) { self::$methodCache[$className] = array_flip(get_class_methods($className)); } $methods = self::$methodCache[$className]; $key2 = ucfirst($key); if (isset($methods['get' . $key2])) { return $object->{'get' . $key2}(); } elseif (isset($methods['is' . $key2])) { return $object->{'is' . $key2}(); } } throw new Exception\RuntimeException(sprintf('Cannot read property "%s".', $key), Exception\RuntimeException::DOES_NOT_EXIST); } /** * Magic __isset method helper. * * @param \TokenReflection\IReflection $object Reflection object * @param string $key Variable name * @return boolean */ final public static function exists(IReflection $object, $key) { try { self::get($object, $key); return true; } catch (RuntimeException $e) { return false; } } } PHP-Token-Reflection-1.4.0/TokenReflection/ReflectionClass.php000066400000000000000000001433121237045466400242140ustar00rootroot00000000000000::] => array( * array(, [])|null * [, ...] * ) * * @var array */ private $traitImports = array(); /** * Stores if the class definition is complete. * * @var array */ private $methods = array(); /** * Constant reflections. * * @var array */ private $constants = array(); /** * Properties reflections. * * @var array */ private $properties = array(); /** * Stores if the class definition is complete. * * @var boolean */ private $definitionComplete = false; /** * Imported namespace/class aliases. * * @var array */ private $aliases = array(); /** * Returns the unqualified name (UQN). * * @return string */ public function getShortName() { $name = $this->getName(); if ($this->namespaceName !== ReflectionNamespace::NO_NAMESPACE_NAME) { $name = substr($name, strlen($this->namespaceName) + 1); } return $name; } /** * Returns the namespace name. * * @return string */ public function getNamespaceName() { return $this->namespaceName === ReflectionNamespace::NO_NAMESPACE_NAME ? '' : $this->namespaceName; } /** * Returns if the class is defined within a namespace. * * @return boolean */ public function inNamespace() { return null !== $this->namespaceName && ReflectionNamespace::NO_NAMESPACE_NAME !== $this->namespaceName; } /** * Returns modifiers. * * @return array */ public function getModifiers() { if (false === $this->modifiersComplete) { if (($this->modifiers & InternalReflectionClass::IS_EXPLICIT_ABSTRACT) && !($this->modifiers & InternalReflectionClass::IS_IMPLICIT_ABSTRACT)) { foreach ($this->getMethods() as $reflectionMethod) { if ($reflectionMethod->isAbstract()) { $this->modifiers |= InternalReflectionClass::IS_IMPLICIT_ABSTRACT; } } if (!empty($this->interfaces)) { $this->modifiers |= InternalReflectionClass::IS_IMPLICIT_ABSTRACT; } } if (!empty($this->interfaces)) { $this->modifiers |= self::IMPLEMENTS_INTERFACES; } if ($this->isInterface() && !empty($this->methods)) { $this->modifiers |= InternalReflectionClass::IS_IMPLICIT_ABSTRACT; } if (!empty($this->traits)) { $this->modifiers |= self::IMPLEMENTS_TRAITS; } $this->modifiersComplete = null === $this->parentClassName || $this->getParentClass()->isComplete(); if ($this->modifiersComplete) { foreach ($this->getInterfaces() as $interface) { if (!$interface->isComplete()) { $this->modifiersComplete = false; break; } } } if ($this->modifiersComplete) { foreach ($this->getTraits() as $trait) { if (!$trait->isComplete()) { $this->modifiersComplete = false; break; } } } } return $this->modifiers; } /** * Returns if the class is abstract. * * @return boolean */ public function isAbstract() { if ($this->modifiers & InternalReflectionClass::IS_EXPLICIT_ABSTRACT) { return true; } elseif ($this->isInterface() && !empty($this->methods)) { return true; } return false; } /** * Returns if the class is final. * * @return boolean */ public function isFinal() { return (bool) ($this->modifiers & InternalReflectionClass::IS_FINAL); } /** * Returns if the class is an interface. * * @return boolean */ public function isInterface() { return (bool) ($this->modifiers & self::IS_INTERFACE); } /** * Returns if the class is an exception or its descendant. * * @return boolean */ public function isException() { return 'Exception' === $this->name || $this->isSubclassOf('Exception'); } /** * Returns if it is possible to create an instance of this class. * * @return boolean */ public function isInstantiable() { if ($this->isInterface() || $this->isAbstract()) { return false; } if (null === ($constructor = $this->getConstructor())) { return true; } return $constructor->isPublic(); } /** * Returns if objects of this class are cloneable. * * Introduced in PHP 5.4. * * @return boolean * @see http://svn.php.net/viewvc/php/php-src/trunk/ext/reflection/php_reflection.c?revision=307971&view=markup#l4059 */ public function isCloneable() { if ($this->isInterface() || $this->isAbstract()) { return false; } if ($this->hasMethod('__clone')) { return $this->getMethod('__clone')->isPublic(); } return true; } /** * Returns if the class is iterateable. * * Returns true if the class implements the Traversable interface. * * @return boolean * @todo traits */ public function isIterateable() { return $this->implementsInterface('Traversable'); } /** * Returns if the current class is a subclass of the given class. * * @param string|object $class Class name or reflection object * @return boolean * @throws \TokenReflection\Exception\RuntimeException If the provided parameter is not a reflection class instance. */ public function isSubclassOf($class) { if (is_object($class)) { if ($class instanceof InternalReflectionClass || $class instanceof IReflectionClass) { $class = $class->getName(); } else { $class = get_class($class); } } if ($class === $this->parentClassName) { return true; } $parent = $this->getParentClass(); return false === $parent ? false : $parent->isSubclassOf($class); } /** * Returns the parent class reflection. * * @return \TokenReflection\ReflectionClass|boolean */ public function getParentClass() { $className = $this->getParentClassName(); if (null === $className) { return false; } return $this->getBroker()->getClass($className); } /** * Returns the parent class name. * * @return string|null */ public function getParentClassName() { return $this->parentClassName; } /** * Returns the parent classes reflections. * * @return array */ public function getParentClasses() { $parent = $this->getParentClass(); if (false === $parent) { return array(); } return array_merge(array($parent->getName() => $parent), $parent->getParentClasses()); } /** * Returns the parent classes names. * * @return array */ public function getParentClassNameList() { $parent = $this->getParentClass(); if (false === $parent) { return array(); } return array_merge(array($parent->getName()), $parent->getParentClassNameList()); } /** * Returns if the class implements the given interface. * * @param string|object $interface Interface name or reflection object * @return boolean * @throws \TokenReflection\Exception\RuntimeException If the provided parameter is not an interface. */ public function implementsInterface($interface) { if (is_object($interface)) { if (!$interface instanceof InternalReflectionClass && !$interface instanceof IReflectionClass) { throw new Exception\RuntimeException(sprintf('Parameter must be a string or an instance of class reflection, "%s" provided.', get_class($interface)), Exception\RuntimeException::INVALID_ARGUMENT, $this); } if (!$interface->isInterface()) { throw new Exception\RuntimeException(sprintf('"%s" is not an interface.', $interfaceName), Exception\RuntimeException::INVALID_ARGUMENT, $this); } $interfaceName = $interface->getName(); } else { $interfaceName = $interface; } return in_array($interfaceName, $this->getInterfaceNames()); } /** * Returns interface reflections. * * @return array */ public function getInterfaces() { $interfaceNames = $this->getInterfaceNames(); if (empty($interfaceNames)) { return array(); } $broker = $this->getBroker(); return array_combine($interfaceNames, array_map(function($interfaceName) use ($broker) { return $broker->getClass($interfaceName); }, $interfaceNames)); } /** * Returns interface names. * * @return array */ public function getInterfaceNames() { $parentClass = $this->getParentClass(); $names = false !== $parentClass ? array_reverse(array_flip($parentClass->getInterfaceNames())) : array(); foreach ($this->interfaces as $interfaceName) { $names[$interfaceName] = true; foreach (array_reverse($this->getBroker()->getClass($interfaceName)->getInterfaceNames()) as $parentInterfaceName) { $names[$parentInterfaceName] = true; } } return array_keys($names); } /** * Returns reflections of interfaces implemented by this class, not its parents. * * @return array */ public function getOwnInterfaces() { $interfaceNames = $this->getOwnInterfaceNames(); if (empty($interfaceNames)) { return array(); } $broker = $this->getBroker(); return array_combine($interfaceNames, array_map(function($interfaceName) use ($broker) { return $broker->getClass($interfaceName); }, $interfaceNames)); } /** * Returns names of interfaces implemented by this class, not its parents. * * @return array */ public function getOwnInterfaceNames() { return $this->interfaces; } /** * Returns the class constructor reflection. * * @return \TokenReflection\ReflectionMethod|null */ public function getConstructor() { foreach ($this->getMethods() as $method) { if ($method->isConstructor()) { return $method; } } return null; } /** * Returns the class destructor reflection. * * @return \TokenReflection\ReflectionMethod|null */ public function getDestructor() { foreach ($this->getMethods() as $method) { if ($method->isDestructor()) { return $method; } } return null; } /** * Returns if the class implements the given method. * * @param string $name Method name * @return boolean */ public function hasMethod($name) { foreach ($this->getMethods() as $method) { if ($name === $method->getName()) { return true; } } return false; } /** * Returns a method reflection. * * @param string $name Method name * @return \TokenReflection\ReflectionMethod * @throws \TokenReflection\Exception\RuntimeException If the requested method does not exist. */ public function getMethod($name) { if (isset($this->methods[$name])) { return $this->methods[$name]; } foreach ($this->getMethods() as $method) { if ($name === $method->getName()) { return $method; } } throw new Exception\RuntimeException(sprintf('There is no method "%s".', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this); } /** * Returns method reflections. * * @param integer $filter Methods filter * @return array */ public function getMethods($filter = null) { $methods = $this->methods; foreach ($this->getTraitMethods() as $traitMethod) { if (!isset($methods[$traitMethod->getName()])) { $methods[$traitMethod->getName()] = $traitMethod; } } if (null !== $this->parentClassName) { foreach ($this->getParentClass()->getMethods(null) as $parentMethod) { if (!isset($methods[$parentMethod->getName()])) { $methods[$parentMethod->getName()] = $parentMethod; } } } foreach ($this->getOwnInterfaces() as $interface) { foreach ($interface->getMethods(null) as $parentMethod) { if (!isset($methods[$parentMethod->getName()])) { $methods[$parentMethod->getName()] = $parentMethod; } } } if (null !== $filter) { $methods = array_filter($methods, function(IReflectionMethod $method) use ($filter) { return $method->is($filter); }); } return array_values($methods); } /** * Returns if the class implements (and not its parents) the given method. * * @param string $name Method name * @return boolean */ public function hasOwnMethod($name) { return isset($this->methods[$name]); } /** * Returns reflections of methods declared by this class, not its parents. * * @param integer $filter Methods filter * @return array */ public function getOwnMethods($filter = null) { $methods = $this->methods; if (null !== $filter) { $methods = array_filter($methods, function(ReflectionMethod $method) use ($filter) { return $method->is($filter); }); } return array_values($methods); } /** * Returns if the class imports the given method from traits. * * @param string $name Method name * @return boolean */ public function hasTraitMethod($name) { if (isset($this->methods[$name])) { return false; } foreach ($this->getOwnTraits() as $trait) { if ($trait->hasMethod($name)) { return true; } } return false; } /** * Returns reflections of method imported from traits. * * @param integer $filter Methods filter * @return array * @throws \TokenReflection\Exception\RuntimeException If trait method was already imported. */ public function getTraitMethods($filter = null) { $methods = array(); foreach ($this->getOwnTraits() as $trait) { $traitName = $trait->getName(); foreach ($trait->getMethods(null) as $traitMethod) { $methodName = $traitMethod->getName(); $imports = array(); if (isset($this->traitImports[$traitName . '::' . $methodName])) { $imports = $this->traitImports[$traitName . '::' . $methodName]; } if (isset($this->traitImports[$methodName])) { $imports = empty($imports) ? $this->traitImports[$methodName] : array_merge($imports, $this->traitImports[$methodName]); } foreach ($imports as $import) { if (null !== $import) { list($newName, $accessLevel) = $import; if ('' === $newName) { $newName = $methodName; $imports[] = null; } if (!isset($this->methods[$newName])) { if (isset($methods[$newName])) { throw new Exception\RuntimeException(sprintf('Trait method "%s" was already imported.', $newName), Exception\RuntimeException::ALREADY_EXISTS, $this); } $methods[$newName] = $traitMethod->alias($this, $newName, $accessLevel); } } } if (!in_array(null, $imports)) { if (!isset($this->methods[$methodName])) { if (isset($methods[$methodName])) { throw new Exception\RuntimeException(sprintf('Trait method "%s" was already imported.', $methodName), Exception\RuntimeException::ALREADY_EXISTS, $this); } $methods[$methodName] = $traitMethod->alias($this); } } } } if (null !== $filter) { $methods = array_filter($methods, function(IReflectionMethod $method) use ($filter) { return (bool) ($method->getModifiers() & $filter); }); } return array_values($methods); } /** * Returns if the class defines the given constant. * * @param string $name Constant name. * @return boolean */ public function hasConstant($name) { if (isset($this->constants[$name])) { return true; } foreach ($this->getConstantReflections() as $constant) { if ($name === $constant->getName()) { return true; } } return false; } /** * Returns a constant value. * * @param string $name Constant name * @return mixed|false */ public function getConstant($name) { try { return $this->getConstantReflection($name)->getValue(); } catch (Exception\BaseException $e) { return false; } } /** * Returns a constant reflection. * * @param string $name Constant name * @return \TokenReflection\ReflectionConstant * @throws \TokenReflection\Exception\RuntimeException If the requested constant does not exist. */ public function getConstantReflection($name) { if (isset($this->constants[$name])) { return $this->constants[$name]; } foreach ($this->getConstantReflections() as $constant) { if ($name === $constant->getName()) { return $constant; } } throw new Exception\RuntimeException(sprintf('There is no constant "%s".', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this); } /** * Returns constant values. * * @return array */ public function getConstants() { $constants = array(); foreach ($this->getConstantReflections() as $constant) { $constants[$constant->getName()] = $constant->getValue(); } return $constants; } /** * Returns constant reflections. * * @return array */ public function getConstantReflections() { if (null === $this->parentClassName && empty($this->interfaces)) { return array_values($this->constants); } else { $reflections = array_values($this->constants); if (null !== $this->parentClassName) { $reflections = array_merge($reflections, $this->getParentClass()->getConstantReflections()); } foreach ($this->getOwnInterfaces() as $interface) { $reflections = array_merge($reflections, $interface->getConstantReflections()); } return $reflections; } } /** * Returns if the class (and not its parents) defines the given constant. * * @param string $name Constant name. * @return boolean */ public function hasOwnConstant($name) { return isset($this->constants[$name]); } /** * Returns constants declared by this class, not by its parents. * * @return array */ public function getOwnConstants() { return array_map(function(ReflectionConstant $constant) { return $constant->getValue(); }, $this->constants); } /** * Returns reflections of constants declared by this class, not by its parents. * * @return array */ public function getOwnConstantReflections() { return array_values($this->constants); } /** * Returns if the class defines the given property. * * @param string $name Property name * @return boolean */ public function hasProperty($name) { foreach ($this->getProperties() as $property) { if ($name === $property->getName()) { return true; } } return false; } /** * Return a property reflection. * * @param string $name Property name * @return \TokenReflection\ReflectionProperty * @throws \TokenReflection\Exception\RuntimeException If the requested property does not exist. */ public function getProperty($name) { if (isset($this->properties[$name])) { return $this->properties[$name]; } foreach ($this->getProperties() as $property) { if ($name === $property->getName()) { return $property; } } throw new Exception\RuntimeException(sprintf('There is no property "%s".', $name, $this->name), Exception\RuntimeException::DOES_NOT_EXIST, $this); } /** * Returns property reflections. * * @param integer $filter Properties filter * @return array */ public function getProperties($filter = null) { $properties = $this->properties; foreach ($this->getTraitProperties(null) as $traitProperty) { if (!isset($properties[$traitProperty->getName()])) { $properties[$traitProperty->getName()] = $traitProperty->alias($this); } } if (null !== $this->parentClassName) { foreach ($this->getParentClass()->getProperties(null) as $parentProperty) { if (!isset($properties[$parentProperty->getName()])) { $properties[$parentProperty->getName()] = $parentProperty; } } } if (null !== $filter) { $properties = array_filter($properties, function(IReflectionProperty $property) use ($filter) { return (bool) ($property->getModifiers() & $filter); }); } return array_values($properties); } /** * Returns if the class (and not its parents) defines the given property. * * @param string $name Property name * @return boolean */ public function hasOwnProperty($name) { return isset($this->properties[$name]); } /** * Returns reflections of properties declared by this class, not its parents. * * @param integer $filter Properties filter * @return array */ public function getOwnProperties($filter = null) { $properties = $this->properties; if (null !== $filter) { $properties = array_filter($properties, function(ReflectionProperty $property) use ($filter) { return (bool) ($property->getModifiers() & $filter); }); } return array_values($properties); } /** * Returns if the class imports the given property from traits. * * @param string $name Property name * @return boolean */ public function hasTraitProperty($name) { if (isset($this->properties[$name])) { return false; } foreach ($this->getOwnTraits() as $trait) { if ($trait->hasProperty($name)) { return true; } } return false; } /** * Returns reflections of properties imported from traits. * * @param integer $filter Properties filter * @return array */ public function getTraitProperties($filter = null) { $properties = array(); foreach ($this->getOwnTraits() as $trait) { foreach ($trait->getProperties(null) as $traitProperty) { if (!isset($this->properties[$traitProperty->getName()]) && !isset($properties[$traitProperty->getName()])) { $properties[$traitProperty->getName()] = $traitProperty->alias($this); } } } if (null !== $filter) { $properties = array_filter($properties, function(IReflectionProperty $property) use ($filter) { return (bool) ($property->getModifiers() & $filter); }); } return array_values($properties); } /** * Returns default properties. * * @return array */ public function getDefaultProperties() { static $accessLevels = array(InternalReflectionProperty::IS_PUBLIC, InternalReflectionProperty::IS_PROTECTED, InternalReflectionProperty::IS_PRIVATE); $defaults = array(); $properties = $this->getProperties(); foreach (array(true, false) as $static) { foreach ($properties as $property) { foreach ($accessLevels as $level) { if ($property->isStatic() === $static && ($property->getModifiers() & $level)) { $defaults[$property->getName()] = $property->getDefaultValue(); } } } } return $defaults; } /** * Returns static properties reflections. * * @return array */ public function getStaticProperties() { $defaults = array(); foreach ($this->getProperties(InternalReflectionProperty::IS_STATIC) as $property) { if ($property instanceof ReflectionProperty) { $defaults[$property->getName()] = $property->getDefaultValue(); } } return $defaults; } /** * Returns a value of a static property. * * @param string $name Property name * @param mixed $default Default value * @return mixed * @throws \TokenReflection\Exception\RuntimeException If the requested static property does not exist. * @throws \TokenReflection\Exception\RuntimeException If the requested static property is not accessible. */ public function getStaticPropertyValue($name, $default = null) { if ($this->hasProperty($name) && ($property = $this->getProperty($name)) && $property->isStatic()) { if (!$property->isPublic() && !$property->isAccessible()) { throw new Exception\RuntimeException(sprintf('Static property "%s" is not accessible.', $name), Exception\RuntimeException::NOT_ACCESSBILE, $this); } return $property->getDefaultValue(); } throw new Exception\RuntimeException(sprintf('There is no static property "%s".', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this); } /** * Returns traits used by this class. * * @return array */ public function getTraits() { $traitNames = $this->getTraitNames(); if (empty($traitNames)) { return array(); } $broker = $this->getBroker(); return array_combine($traitNames, array_map(function($traitName) use ($broker) { return $broker->getClass($traitName); }, $traitNames)); } /** * Returns traits used by this class and not its parents. * * @return array */ public function getOwnTraits() { $ownTraitNames = $this->getOwnTraitNames(); if (empty($ownTraitNames)) { return array(); } $broker = $this->getBroker(); return array_combine($ownTraitNames, array_map(function($traitName) use ($broker) { return $broker->getClass($traitName); }, $ownTraitNames)); } /** * Returns names of used traits. * * @return array */ public function getTraitNames() { $parentClass = $this->getParentClass(); $names = $parentClass ? $parentClass->getTraitNames() : array(); foreach ($this->traits as $traitName) { $names[] = $traitName; } return array_unique($names); } /** * Returns names of traits used by this class an not its parents. * * @return array */ public function getOwnTraitNames() { return $this->traits; } /** * Returns method aliases from traits. * * @return array */ public function getTraitAliases() { return $this->traitAliases; } /** * Returns if the class is a trait. * * @return boolean */ public function isTrait() { return self::IS_TRAIT === $this->type; } /** * Returns if the class definition is valid. * * @return boolean */ public function isValid() { if (null !== $this->parentClassName && !$this->getParentClass()->isValid()) { return false; } foreach ($this->getInterfaces() as $interface) { if (!$interface->isValid()) { return false; } } foreach ($this->getTraits() as $trait) { if (!$trait->isValid()) { return false; } } return true; } /** * Returns if the class uses a particular trait. * * @param \ReflectionClass|\TokenReflection\IReflectionClass|string $trait Trait reflection or name * @return boolean * @throws \TokenReflection\Exception\RuntimeException If an invalid parameter was provided. */ public function usesTrait($trait) { if (is_object($trait)) { if (!$trait instanceof InternalReflectionClass && !$trait instanceof IReflectionClass) { throw new Exception\RuntimeException(sprintf('Parameter must be a string or an instance of trait reflection, "%s" provided.', get_class($trait)), Exception\RuntimeException::INVALID_ARGUMENT, $this); } $traitName = $trait->getName(); if (!$trait->isTrait()) { throw new Exception\RuntimeException(sprintf('"%s" is not a trait.', $traitName), Exception\RuntimeException::INVALID_ARGUMENT, $this); } } else { $reflection = $this->getBroker()->getClass($trait); if (!$reflection->isTrait()) { throw new Exception\RuntimeException(sprintf('"%s" is not a trait.', $trait), Exception\RuntimeException::INVALID_ARGUMENT, $this); } $traitName = $trait; } return in_array($traitName, $this->getTraitNames()); } /** * Returns reflections of direct subclasses. * * @return array */ public function getDirectSubclasses() { $that = $this->name; return array_filter($this->getBroker()->getClasses(), function(ReflectionClass $class) use ($that) { if (!$class->isSubclassOf($that)) { return false; } return null === $class->getParentClassName() || !$class->getParentClass()->isSubClassOf($that); }); } /** * Returns names of direct subclasses. * * @return array */ public function getDirectSubclassNames() { return array_keys($this->getDirectSubclasses()); } /** * Returns reflections of indirect subclasses. * * @return array */ public function getIndirectSubclasses() { $that = $this->name; return array_filter($this->getBroker()->getClasses(), function(ReflectionClass $class) use ($that) { if (!$class->isSubclassOf($that)) { return false; } return null !== $class->getParentClassName() && $class->getParentClass()->isSubClassOf($that); }); } /** * Returns names of indirect subclasses. * * @return array */ public function getIndirectSubclassNames() { return array_keys($this->getIndirectSubclasses()); } /** * Returns reflections of classes directly implementing this interface. * * @return array */ public function getDirectImplementers() { if (!$this->isInterface()) { return array(); } $that = $this->name; return array_filter($this->getBroker()->getClasses(), function(ReflectionClass $class) use ($that) { if ($class->isInterface() || !$class->implementsInterface($that)) { return false; } return null === $class->getParentClassName() || !$class->getParentClass()->implementsInterface($that); }); } /** * Returns names of classes directly implementing this interface. * * @return array */ public function getDirectImplementerNames() { return array_keys($this->getDirectImplementers()); } /** * Returns reflections of classes indirectly implementing this interface. * * @return array */ public function getIndirectImplementers() { if (!$this->isInterface()) { return array(); } $that = $this->name; return array_filter($this->getBroker()->getClasses(), function(ReflectionClass $class) use ($that) { if ($class->isInterface() || !$class->implementsInterface($that)) { return false; } return null !== $class->getParentClassName() && $class->getParentClass()->implementsInterface($that); }); } /** * Returns names of classes indirectly implementing this interface. * * @return array */ public function getIndirectImplementerNames() { return array_keys($this->getIndirectImplementers()); } /** * Returns if the given object is an instance of this class. * * @param object $object Instance * @return boolean * @throws \TokenReflection\Exception\RuntimeException If the provided argument is not an object. */ public function isInstance($object) { if (!is_object($object)) { throw new Exception\RuntimeException(sprintf('Parameter must be an object, "%s" provided.', gettype($object)), Exception\RuntimeException::INVALID_ARGUMENT, $this); } return $this->name === get_class($object) || is_subclass_of($object, $this->getName()); } /** * Creates a new class instance without using a constructor. * * @return object * @throws \TokenReflection\Exception\RuntimeException If the class inherits from an internal class. */ public function newInstanceWithoutConstructor() { if (!class_exists($this->name, true)) { throw new Exception\RuntimeException('Could not create an instance; class does not exist.', Exception\RuntimeException::DOES_NOT_EXIST, $this); } $reflection = new \TokenReflection\Php\ReflectionClass($this->getName(), $this->getBroker()); return $reflection->newInstanceWithoutConstructor(); } /** * Creates a new instance using variable number of parameters. * * Use any number of constructor parameters as function parameters. * * @param mixed $args * @return object */ public function newInstance($args) { return $this->newInstanceArgs(func_get_args()); } /** * Creates a new instance using an array of parameters. * * @param array $args Array of constructor parameters * @return object * @throws \TokenReflection\Exception\RuntimeException If the required class does not exist. */ public function newInstanceArgs(array $args = array()) { if (!class_exists($this->name, true)) { throw new Exception\RuntimeException('Could not create an instance; class does not exist.', Exception\RuntimeException::DOES_NOT_EXIST, $this); } $reflection = new InternalReflectionClass($this->name); return $reflection->newInstanceArgs($args); } /** * Sets a static property value. * * @param string $name Property name * @param mixed $value Property value * @throws \TokenReflection\Exception\RuntimeException If the requested static property does not exist. * @throws \TokenReflection\Exception\RuntimeException If the requested static property is not accessible. */ public function setStaticPropertyValue($name, $value) { if ($this->hasProperty($name) && ($property = $this->getProperty($name)) && $property->isStatic()) { if (!$property->isPublic() && !$property->isAccessible()) { throw new Exception\RuntimeException(sprintf('Static property "%s" is not accessible.', $name), Exception\RuntimeException::NOT_ACCESSBILE, $this); } $property->setDefaultValue($value); return; } throw new Exception\RuntimeException(sprintf('There is no static property "%s".', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this); } /** * Returns the string representation of the reflection object. * * @return string */ public function __toString() { $implements = ''; $interfaceNames = $this->getInterfaceNames(); if (count($interfaceNames) > 0) { $implements = sprintf( ' %s %s', $this->isInterface() ? 'extends' : 'implements', implode(', ', $interfaceNames) ); } $buffer = ''; $count = 0; foreach ($this->getConstantReflections() as $constant) { $buffer .= ' ' . $constant->__toString(); $count++; } $constants = sprintf("\n\n - Constants [%d] {\n%s }", $count, $buffer); $sBuffer = ''; $sCount = 0; $buffer = ''; $count = 0; foreach ($this->getProperties() as $property) { $string = ' ' . preg_replace('~\n(?!$)~', "\n ", $property->__toString()); if ($property->isStatic()) { $sBuffer .= $string; $sCount++; } else { $buffer .= $string; $count++; } } $staticProperties = sprintf("\n\n - Static properties [%d] {\n%s }", $sCount, $sBuffer); $properties = sprintf("\n\n - Properties [%d] {\n%s }", $count, $buffer); $sBuffer = ''; $sCount = 0; $buffer = ''; $count = 0; foreach ($this->getMethods() as $method) { // Skip private methods of parent classes if ($method->getDeclaringClassName() !== $this->getName() && $method->isPrivate()) { continue; } // Indent $string = "\n "; $string .= preg_replace('~\n(?!$|\n|\s*\*)~', "\n ", $method->__toString()); // Add inherits if ($method->getDeclaringClassName() !== $this->getName()) { $string = preg_replace( array('~Method [ <[\w:]+~', '~, overwrites[^,]+~'), array('\0, inherits ' . $method->getDeclaringClassName(), ''), $string ); } if ($method->isStatic()) { $sBuffer .= $string; $sCount++; } else { $buffer .= $string; $count++; } } $staticMethods = sprintf("\n\n - Static methods [%d] {\n%s }", $sCount, ltrim($sBuffer, "\n")); $methods = sprintf("\n\n - Methods [%d] {\n%s }", $count, ltrim($buffer, "\n")); return sprintf( "%s%s [ %s %s%s%s %s%s%s ] {\n @@ %s %d-%d%s%s%s%s%s\n}\n", $this->getDocComment() ? $this->getDocComment() . "\n" : '', $this->isInterface() ? 'Interface' : 'Class', $this->isIterateable() ? ' ' : '', $this->isAbstract() && !$this->isInterface() ? 'abstract ' : '', $this->isFinal() ? 'final ' : '', $this->isInterface() ? 'interface' : 'class', $this->getName(), null !== $this->getParentClassName() ? ' extends ' . $this->getParentClassName() : '', $implements, $this->getFileName(), $this->getStartLine(), $this->getEndLine(), $constants, $staticProperties, $staticMethods, $properties, $methods ); } /** * Exports a reflected object. * * @param \TokenReflection\Broker $broker Broker instance * @param string|object $className Class name or class instance * @param boolean $return Return the export instead of outputting it * @return string|null * @throws \TokenReflection\Exception\RuntimeException If requested parameter doesn't exist. */ public static function export(Broker $broker, $className, $return = false) { if (is_object($className)) { $className = get_class($className); } $class = $broker->getClass($className); if ($class instanceof Invalid\ReflectionClass) { throw new Exception\RuntimeException('Class is invalid.', Exception\RuntimeException::UNSUPPORTED); } elseif ($class instanceof Dummy\ReflectionClass) { throw new Exception\RuntimeException('Class does not exist.', Exception\RuntimeException::DOES_NOT_EXIST); } if ($return) { return $class->__toString(); } echo $class->__toString(); } /** * Returns if the class definition is complete. * * @return boolean */ public function isComplete() { if (!$this->definitionComplete) { if (null !== $this->parentClassName && !$this->getParentClass()->isComplete()) { return false; } foreach ($this->getOwnInterfaces() as $interface) { if (!$interface->isComplete()) { return false; } } $this->definitionComplete = true; } return $this->definitionComplete; } /** * Returns imported namespaces and aliases from the declaring namespace. * * @return array */ public function getNamespaceAliases() { return $this->aliases; } /** * Processes the parent reflection object. * * @param \TokenReflection\IReflection $parent Parent reflection object * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionClass * @throws \TokenReflection\ParseException On invalid parent reflection provided */ protected function processParent(IReflection $parent, Stream $tokenStream) { if (!$parent instanceof ReflectionFileNamespace) { throw new Exception\ParseException($this, $tokenStream, sprintf('Invalid parent reflection provided: "%s".', get_class($parent)), Exception\ParseException::INVALID_PARENT); } $this->namespaceName = $parent->getName(); $this->aliases = $parent->getNamespaceAliases(); return parent::processParent($parent, $tokenStream); } /** * Parses reflected element metadata from the token stream. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @param \TokenReflection\IReflection $parent Parent reflection object * @return \TokenReflection\ReflectionClass */ protected function parse(Stream $tokenStream, IReflection $parent) { return $this ->parseModifiers($tokenStream) ->parseName($tokenStream) ->parseParent($tokenStream, $parent) ->parseInterfaces($tokenStream, $parent); } /** * Parses class modifiers (abstract, final) and class type (class, interface). * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionClass */ private function parseModifiers(Stream $tokenStream) { while (true) { switch ($tokenStream->getType()) { case null: break 2; case T_ABSTRACT: $this->modifiers = InternalReflectionClass::IS_EXPLICIT_ABSTRACT; break; case T_FINAL: $this->modifiers = InternalReflectionClass::IS_FINAL; break; case T_INTERFACE: $this->modifiers = self::IS_INTERFACE; $this->type = self::IS_INTERFACE; $tokenStream->skipWhitespaces(true); break 2; case T_TRAIT: $this->modifiers = self::IS_TRAIT; $this->type = self::IS_TRAIT; $tokenStream->skipWhitespaces(true); break 2; case T_CLASS: $tokenStream->skipWhitespaces(true); break 2; default: break; } $tokenStream->skipWhitespaces(true); } return $this; } /** * Parses the class/interface name. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionClass * @throws \TokenReflection\Exception\ParseException If the class name could not be determined. */ protected function parseName(Stream $tokenStream) { if (!$tokenStream->is(T_STRING)) { throw new Exception\ParseException($this, $tokenStream, 'Unexpected token found.', Exception\ParseException::UNEXPECTED_TOKEN); } if ($this->namespaceName === ReflectionNamespace::NO_NAMESPACE_NAME) { $this->name = $tokenStream->getTokenValue(); } else { $this->name = $this->namespaceName . '\\' . $tokenStream->getTokenValue(); } $tokenStream->skipWhitespaces(true); return $this; } /** * Parses the parent class. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @param \TokenReflection\IReflection $parent Parent reflection object * @return \TokenReflection\ReflectionClass */ private function parseParent(Stream $tokenStream, ReflectionElement $parent = null) { if (!$tokenStream->is(T_EXTENDS)) { return $this; } while (true) { $tokenStream->skipWhitespaces(true); $parentClassName = ''; while (true) { switch ($tokenStream->getType()) { case T_STRING: case T_NS_SEPARATOR: $parentClassName .= $tokenStream->getTokenValue(); break; default: break 2; } $tokenStream->skipWhitespaces(true); } $parentClassName = Resolver::resolveClassFQN($parentClassName, $this->aliases, $this->namespaceName); if ($this->isInterface()) { $this->interfaces[] = $parentClassName; if (',' === $tokenStream->getTokenValue()) { continue; } } else { $this->parentClassName = $parentClassName; } break; } return $this; } /** * Parses implemented interfaces. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @param \TokenReflection\IReflection $parent Parent reflection object * @return \TokenReflection\ReflectionClass * @throws \TokenReflection\Exception\ParseException On error while parsing interfaces. */ private function parseInterfaces(Stream $tokenStream, ReflectionElement $parent = null) { if (!$tokenStream->is(T_IMPLEMENTS)) { return $this; } if ($this->isInterface()) { throw new Exception\ParseException($this, $tokenStream, 'Interfaces cannot implement interfaces.', Exception\ParseException::LOGICAL_ERROR); } while (true) { $interfaceName = ''; $tokenStream->skipWhitespaces(true); while (true) { switch ($tokenStream->getType()) { case T_STRING: case T_NS_SEPARATOR: $interfaceName .= $tokenStream->getTokenValue(); break; default: break 2; } $tokenStream->skipWhitespaces(true); } $this->interfaces[] = Resolver::resolveClassFQN($interfaceName, $this->aliases, $this->namespaceName); $type = $tokenStream->getType(); if ('{' === $type) { break; } elseif (',' !== $type) { throw new Exception\ParseException($this, $tokenStream, 'Unexpected token found, expected "{" or ";".', Exception\ParseException::UNEXPECTED_TOKEN); } } return $this; } /** * Parses child reflection objects from the token stream. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @param \TokenReflection\IReflection $parent Parent reflection object * @return \TokenReflection\ReflectionClass * @throws \TokenReflection\Exception\ParseException If a parse error was detected. */ protected function parseChildren(Stream $tokenStream, IReflection $parent) { while (true) { switch ($type = $tokenStream->getType()) { case null: break 2; case T_COMMENT: case T_DOC_COMMENT: $docblock = $tokenStream->getTokenValue(); if (preg_match('~^' . preg_quote(self::DOCBLOCK_TEMPLATE_START, '~') . '~', $docblock)) { array_unshift($this->docblockTemplates, new ReflectionAnnotation($this, $docblock)); } elseif (self::DOCBLOCK_TEMPLATE_END === $docblock) { array_shift($this->docblockTemplates); } $tokenStream->next(); break; case '}': break 2; case T_PUBLIC: case T_PRIVATE: case T_PROTECTED: case T_STATIC: case T_VAR: case T_VARIABLE: static $searching = array(T_VARIABLE => true, T_FUNCTION => true); if (T_VAR !== $tokenStream->getType()) { $position = $tokenStream->key(); while (null !== ($type = $tokenStream->getType($position)) && !isset($searching[$type])) { $position++; } } if (T_VARIABLE === $type || T_VAR === $type) { $property = new ReflectionProperty($tokenStream, $this->getBroker(), $this); $this->properties[$property->getName()] = $property; $tokenStream->next(); break; } // Break missing on purpose case T_FINAL: case T_ABSTRACT: case T_FUNCTION: $method = new ReflectionMethod($tokenStream, $this->getBroker(), $this); $this->methods[$method->getName()] = $method; $tokenStream->next(); break; case T_CONST: $tokenStream->skipWhitespaces(true); while ($tokenStream->is(T_STRING)) { $constant = new ReflectionConstant($tokenStream, $this->getBroker(), $this); $this->constants[$constant->getName()] = $constant; if ($tokenStream->is(',')) { $tokenStream->skipWhitespaces(true); } else { $tokenStream->next(); } } break; case T_USE: $tokenStream->skipWhitespaces(true); while (true) { $traitName = ''; $type = $tokenStream->getType(); while (T_STRING === $type || T_NS_SEPARATOR === $type) { $traitName .= $tokenStream->getTokenValue(); $type = $tokenStream->skipWhitespaces(true)->getType(); } if ('' === trim($traitName, '\\')) { throw new Exception\ParseException($this, $tokenStream, 'An empty trait name found.', Exception\ParseException::LOGICAL_ERROR); } $this->traits[] = Resolver::resolveClassFQN($traitName, $this->aliases, $this->namespaceName); if (';' === $type) { // End of "use" $tokenStream->skipWhitespaces(); break; } elseif (',' === $type) { // Next trait name follows $tokenStream->skipWhitespaces(); continue; } elseif ('{' !== $type) { // Unexpected token throw new Exception\ParseException($this, $tokenStream, 'Unexpected token found: "%s".', Exception\ParseException::UNEXPECTED_TOKEN); } // Aliases definition $type = $tokenStream->skipWhitespaces(true)->getType(); while (true) { if ('}' === $type) { $tokenStream->skipWhitespaces(); break 2; } $leftSide = ''; $rightSide = array('', null); $alias = true; while (T_STRING === $type || T_NS_SEPARATOR === $type || T_DOUBLE_COLON === $type) { $leftSide .= $tokenStream->getTokenValue(); $type = $tokenStream->skipWhitespaces(true)->getType(); } if (T_INSTEADOF === $type) { $alias = false; } elseif (T_AS !== $type) { throw new Exception\ParseException($this, $tokenStream, 'Unexpected token found.', Exception\ParseException::UNEXPECTED_TOKEN); } $type = $tokenStream->skipWhitespaces(true)->getType(); if (T_PUBLIC === $type || T_PROTECTED === $type || T_PRIVATE === $type) { if (!$alias) { throw new Exception\ParseException($this, $tokenStream, 'Unexpected token found.', Exception\ParseException::UNEXPECTED_TOKEN); } switch ($type) { case T_PUBLIC: $type = InternalReflectionMethod::IS_PUBLIC; break; case T_PROTECTED: $type = InternalReflectionMethod::IS_PROTECTED; break; case T_PRIVATE: $type = InternalReflectionMethod::IS_PRIVATE; break; default: break; } $rightSide[1] = $type; $type = $tokenStream->skipWhitespaces(true)->getType(); } while (T_STRING === $type || (T_NS_SEPARATOR === $type && !$alias)) { $rightSide[0] .= $tokenStream->getTokenValue(); $type = $tokenStream->skipWhitespaces(true)->getType(); } if (empty($leftSide)) { throw new Exception\ParseException($this, $tokenStream, 'An empty method name was found.', Exception\ParseException::LOGICAL_ERROR); } if ($alias) { // Alias if ($pos = strpos($leftSide, '::')) { $methodName = substr($leftSide, $pos + 2); $className = Resolver::resolveClassFQN(substr($leftSide, 0, $pos), $this->aliases, $this->namespaceName); $leftSide = $className . '::' . $methodName; $this->traitAliases[$rightSide[0]] = $leftSide; } else { $this->traitAliases[$rightSide[0]] = '(null)::' . $leftSide; } $this->traitImports[$leftSide][] = $rightSide; } else { // Insteadof if ($pos = strpos($leftSide, '::')) { $methodName = substr($leftSide, $pos + 2); } else { throw new Exception\ParseException($this, $tokenStream, 'A T_DOUBLE_COLON has to be present when using T_INSTEADOF.', Exception\ParseException::UNEXPECTED_TOKEN); } $this->traitImports[Resolver::resolveClassFQN($rightSide[0], $this->aliases, $this->namespaceName) . '::' . $methodName][] = null; } if (',' === $type) { $tokenStream->skipWhitespaces(true); continue; } elseif (';' !== $type) { throw new Exception\ParseException($this, $tokenStream, 'Unexpected token found.', Exception\ParseException::UNEXPECTED_TOKEN); } $type = $tokenStream->skipWhitespaces()->getType(); } } break; default: $tokenStream->next(); break; } } return $this; } } PHP-Token-Reflection-1.4.0/TokenReflection/ReflectionConstant.php000066400000000000000000000237601237045466400247440ustar00rootroot00000000000000getName(); if (null !== $this->namespaceName && $this->namespaceName !== ReflectionNamespace::NO_NAMESPACE_NAME) { $name = substr($name, strlen($this->namespaceName) + 1); } return $name; } /** * Returns the name of the declaring class. * * @return string|null */ public function getDeclaringClassName() { return $this->declaringClassName; } /** * Returns a reflection of the declaring class. * * @return \TokenReflection\ReflectionClass|null */ public function getDeclaringClass() { if (null === $this->declaringClassName) { return null; } return $this->getBroker()->getClass($this->declaringClassName); } /** * Returns the namespace name. * * @return string */ public function getNamespaceName() { return null === $this->namespaceName || $this->namespaceName === ReflectionNamespace::NO_NAMESPACE_NAME ? '' : $this->namespaceName; } /** * Returns if the class is defined within a namespace. * * @return boolean */ public function inNamespace() { return '' !== $this->getNamespaceName(); } /** * Returns the constant value. * * @return mixed */ public function getValue() { if (is_array($this->valueDefinition)) { $this->value = Resolver::getValueDefinition($this->valueDefinition, $this); $this->valueDefinition = Resolver::getSourceCode($this->valueDefinition); } return $this->value; } /** * Returns the constant value definition. * * @return string */ public function getValueDefinition() { return is_array($this->valueDefinition) ? Resolver::getSourceCode($this->valueDefinition) : $this->valueDefinition; } /** * Returns the originaly provided value definition. * * @return string */ public function getOriginalValueDefinition() { return $this->valueDefinition; } /** * Returns the string representation of the reflection object. * * @return string */ public function __toString() { return sprintf( "Constant [ %s %s ] { %s }\n", strtolower(gettype($this->getValue())), $this->getName(), $this->getValue() ); } /** * Exports a reflected object. * * @param \TokenReflection\Broker $broker Broker instance * @param string|object|null $class Class name, class instance or null * @param string $constant Constant name * @param boolean $return Return the export instead of outputting it * @return string|null * @throws \TokenReflection\Exception\RuntimeException If requested parameter doesn't exist. */ public static function export(Broker $broker, $class, $constant, $return = false) { $className = is_object($class) ? get_class($class) : $class; $constantName = $constant; if (null === $className) { $constant = $broker->getConstant($constantName); if (null === $constant) { throw new Exception\RuntimeException('Constant does not exist.', Exception\RuntimeException::DOES_NOT_EXIST); } } else { $class = $broker->getClass($className); if ($class instanceof Invalid\ReflectionClass) { throw new Exception\RuntimeException('Class is invalid.', Exception\RuntimeException::UNSUPPORTED); } elseif ($class instanceof Dummy\ReflectionClass) { throw new Exception\RuntimeException('Class does not exist.', Exception\RuntimeException::DOES_NOT_EXIST, $class); } $constant = $class->getConstantReflection($constantName); } if ($return) { return $constant->__toString(); } echo $constant->__toString(); } /** * Returns imported namespaces and aliases from the declaring namespace. * * @return array */ public function getNamespaceAliases() { return null === $this->declaringClassName ? $this->aliases : $this->getDeclaringClass()->getNamespaceAliases(); } /** * Returns an element pretty (docblock compatible) name. * * @return string */ public function getPrettyName() { return null === $this->declaringClassName ? parent::getPrettyName() : sprintf('%s::%s', $this->declaringClassName, $this->name); } /** * Returns if the constant definition is valid. * * @return boolean */ public function isValid() { return true; } /** * Processes the parent reflection object. * * @param \TokenReflection\IReflection $parent Parent reflection object * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionElement * @throws \TokenReflection\Exception\ParseException If an invalid parent reflection object was provided. */ protected function processParent(IReflection $parent, Stream $tokenStream) { if ($parent instanceof ReflectionFileNamespace) { $this->namespaceName = $parent->getName(); $this->aliases = $parent->getNamespaceAliases(); } elseif ($parent instanceof ReflectionClass) { $this->declaringClassName = $parent->getName(); } else { throw new Exception\ParseException($this, $tokenStream, sprintf('Invalid parent reflection provided: "%s".', get_class($parent)), Exception\ParseException::INVALID_PARENT); } return parent::processParent($parent, $tokenStream); } /** * Find the appropriate docblock. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @param \TokenReflection\IReflection $parent Parent reflection * @return \TokenReflection\ReflectionConstant */ protected function parseDocComment(Stream $tokenStream, IReflection $parent) { $position = $tokenStream->key() - 1; while ($position > 0 && !$tokenStream->is(T_CONST, $position)) { $position--; } $actual = $tokenStream->key(); parent::parseDocComment($tokenStream->seek($position), $parent); $tokenStream->seek($actual); return $this; } /** * Parses reflected element metadata from the token stream. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @param \TokenReflection\IReflection $parent Parent reflection object * @return \TokenReflection\ReflectionConstant */ protected function parse(Stream $tokenStream, IReflection $parent) { if ($tokenStream->is(T_CONST)) { $tokenStream->skipWhitespaces(true); } if (false === $this->docComment->getDocComment()) { parent::parseDocComment($tokenStream, $parent); } return $this ->parseName($tokenStream) ->parseValue($tokenStream, $parent); } /** * Parses the constant name. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionConstant * @throws \TokenReflection\Exception\ParseReflection If the constant name could not be determined. */ protected function parseName(Stream $tokenStream) { if (!$tokenStream->is(T_STRING)) { throw new Exception\ParseException($this, $tokenStream, 'The constant name could not be determined.', Exception\ParseException::LOGICAL_ERROR); } if (null === $this->namespaceName || $this->namespaceName === ReflectionNamespace::NO_NAMESPACE_NAME) { $this->name = $tokenStream->getTokenValue(); } else { $this->name = $this->namespaceName . '\\' . $tokenStream->getTokenValue(); } $tokenStream->skipWhitespaces(true); return $this; } /** * Parses the constant value. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @param \TokenReflection\IReflection $parent Parent reflection object * @return \TokenReflection\ReflectionConstant * @throws \TokenReflection\Exception\ParseException If the constant value could not be determined. */ private function parseValue(Stream $tokenStream, IReflection $parent) { if (!$tokenStream->is('=')) { throw new Exception\ParseException($this, $tokenStream, 'Could not find the definition start.', Exception\ParseException::UNEXPECTED_TOKEN); } $tokenStream->skipWhitespaces(true); static $acceptedTokens = array( '-' => true, '+' => true, T_STRING => true, T_NS_SEPARATOR => true, T_CONSTANT_ENCAPSED_STRING => true, T_DNUMBER => true, T_LNUMBER => true, T_DOUBLE_COLON => true, T_CLASS_C => true, T_DIR => true, T_FILE => true, T_FUNC_C => true, T_LINE => true, T_METHOD_C => true, T_NS_C => true, T_TRAIT_C => true ); while (null !== ($type = $tokenStream->getType())) { if (T_START_HEREDOC === $type) { $this->valueDefinition[] = $tokenStream->current(); while (null !== $type && T_END_HEREDOC !== $type) { $tokenStream->next(); $this->valueDefinition[] = $tokenStream->current(); $type = $tokenStream->getType(); }; $tokenStream->next(); } elseif (isset($acceptedTokens[$type])) { $this->valueDefinition[] = $tokenStream->current(); $tokenStream->next(); } elseif ($tokenStream->isWhitespace(true)) { $tokenStream->skipWhitespaces(true); } else { break; } } if (empty($this->valueDefinition)) { throw new Exception\ParseException($this, $tokenStream, 'Value definition is empty.', Exception\ParseException::LOGICAL_ERROR); } $value = $tokenStream->getTokenValue(); if (null === $type || (',' !== $value && ';' !== $value)) { throw new Exception\ParseException($this, $tokenStream, 'Invalid value definition.', Exception\ParseException::LOGICAL_ERROR); } return $this; } } PHP-Token-Reflection-1.4.0/TokenReflection/ReflectionElement.php000066400000000000000000000204551237045466400245420ustar00rootroot00000000000000count()) { throw new Exception\ParseException($this, $tokenStream, 'Reflection token stream must not be empty.', Exception\ParseException::INVALID_ARGUMENT); } parent::__construct($tokenStream, $broker, $parent); } /** * Parses the token substream. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @param \TokenReflection\IReflection $parent Parent reflection object */ final protected function parseStream(Stream $tokenStream, IReflection $parent = null) { $this->fileName = $tokenStream->getFileName(); $this ->processParent($parent, $tokenStream) ->parseStartLine($tokenStream) ->parseDocComment($tokenStream, $parent) ->parse($tokenStream, $parent) ->parseChildren($tokenStream, $parent) ->parseEndLine($tokenStream); } /** * Returns the file name the reflection object is defined in. * * @return string */ public function getFileName() { return $this->fileName; } /** * Returns a file reflection. * * @return \TokenReflection\ReflectionFile * @throws \TokenReflection\Exception\RuntimeException If the file is not stored inside the broker */ public function getFileReflection() { return $this->getBroker()->getFile($this->fileName); } /** * Returns the definition start line number in the file. * * @return integer */ public function getStartLine() { return $this->startLine; } /** * Returns the definition end line number in the file. * * @return integer */ public function getEndLine() { return $this->endLine; } /** * Returns the PHP extension reflection. * * Alwyas returns null - everything is user defined. * * @return null */ public function getExtension() { return null; } /** * Returns the PHP extension name. * * Alwyas returns false - everything is user defined. * * @return boolean */ public function getExtensionName() { return false; } /** * Returns the appropriate source code part. * * @return string */ public function getSource() { return $this->broker->getFileTokens($this->getFileName())->getSourcePart($this->startPosition, $this->endPosition); } /** * Returns the start position in the file token stream. * * @return integer */ public function getStartPosition() { return $this->startPosition; } /** * Returns the end position in the file token stream. * * @return integer */ public function getEndPosition() { return $this->endPosition; } /** * Returns the stack of docblock templates. * * @return array */ protected function getDocblockTemplates() { return $this->docblockTemplates; } /** * Processes the parent reflection object. * * @param \TokenReflection\Reflection $parent Parent reflection object * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionElement */ protected function processParent(IReflection $parent, Stream $tokenStream) { // To be defined in child classes return $this; } /** * Find the appropriate docblock. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @param \TokenReflection\IReflection $parent Parent reflection * @return \TokenReflection\ReflectionElement */ protected function parseDocComment(Stream $tokenStream, IReflection $parent) { if ($this instanceof ReflectionParameter) { $this->docComment = new ReflectionAnnotation($this); return $this; } $position = $tokenStream->key(); if ($tokenStream->is(T_DOC_COMMENT, $position - 1)) { $value = $tokenStream->getTokenValue($position - 1); if (self::DOCBLOCK_TEMPLATE_END !== $value) { $this->docComment = new ReflectionAnnotation($this, $value); $this->startPosition--; } } elseif ($tokenStream->is(T_DOC_COMMENT, $position - 2)) { $value = $tokenStream->getTokenValue($position - 2); if (self::DOCBLOCK_TEMPLATE_END !== $value) { $this->docComment = new ReflectionAnnotation($this, $value); $this->startPosition -= 2; } } elseif ($tokenStream->is(T_COMMENT, $position - 1) && preg_match('~^' . preg_quote(self::DOCBLOCK_TEMPLATE_START, '~') . '~', $tokenStream->getTokenValue($position - 1))) { $this->docComment = new ReflectionAnnotation($this, $tokenStream->getTokenValue($position - 1)); $this->startPosition--; } elseif ($tokenStream->is(T_COMMENT, $position - 2) && preg_match('~^' . preg_quote(self::DOCBLOCK_TEMPLATE_START, '~') . '~', $tokenStream->getTokenValue($position - 2))) { $this->docComment = new ReflectionAnnotation($this, $tokenStream->getTokenValue($position - 2)); $this->startPosition -= 2; } if (null === $this->docComment) { $this->docComment = new ReflectionAnnotation($this); } if ($parent instanceof ReflectionElement) { $this->docComment->setTemplates($parent->getDocblockTemplates()); } return $this; } /** * Saves the start line number. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token susbtream * @return \TokenReflection\ReflectionElement */ private final function parseStartLine(Stream $tokenStream) { $token = $tokenStream->current(); $this->startLine = $token[2]; $this->startPosition = $tokenStream->key(); return $this; } /** * Saves the end line number. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token susbtream * @return \TokenReflection\ReflectionElement */ private final function parseEndLine(Stream $tokenStream) { $token = $tokenStream->current(); $this->endLine = $token[2]; $this->endPosition = $tokenStream->key(); return $this; } /** * Parses reflected element metadata from the token stream. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @param \TokenReflection\IReflection $parent Parent reflection object * @return \TokenReflection\ReflectionElement */ abstract protected function parse(Stream $tokenStream, IReflection $parent); /** * Parses the reflection object name. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionElement */ abstract protected function parseName(Stream $tokenStream); /** * Parses child reflection objects from the token stream. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @param \TokenReflection\Reflection $parent Parent reflection object * @return \TokenReflection\ReflectionElement */ protected function parseChildren(Stream $tokenStream, IReflection $parent) { // To be defined in child classes return $this; } } PHP-Token-Reflection-1.4.0/TokenReflection/ReflectionFile.php000066400000000000000000000073761237045466400240370ustar00rootroot00000000000000namespaces; } /** * Returns the string representation of the reflection object. * * @throws \TokenReflection\Exception\RuntimeException If the method is called, because it's unsupported. */ public function __toString() { throw new Exception\RuntimeException('Casting to string is not supported.', Exception\RuntimeException::UNSUPPORTED, $this); } /** * Exports a reflected object. * * @param \TokenReflection\Broker $broker Broker instance * @param string $argument Reflection object name * @param boolean $return Return the export instead of outputting it * @throws \TokenReflection\Exception\RuntimeException If the method is called, because it's unsupported. */ public static function export(Broker $broker, $argument, $return = false) { throw new Exception\RuntimeException('Export is not supported.', Exception\RuntimeException::UNSUPPORTED); } /** * Outputs the file source code. * * @return string */ public function getSource() { return (string) $this->broker->getFileTokens($this->getName()); } /** * Parses the token substream and prepares namespace reflections from the file. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @param \TokenReflection\IReflection $parent Parent reflection object * @return \TokenReflection\ReflectionFile */ protected function parseStream(Stream $tokenStream, IReflection $parent = null) { $this->name = $tokenStream->getFileName(); if (1 >= $tokenStream->count()) { // No PHP content $this->docComment = new ReflectionAnnotation($this, null); return $this; } $docCommentPosition = null; if (!$tokenStream->is(T_OPEN_TAG)) { $this->namespaces[] = new ReflectionFileNamespace($tokenStream, $this->broker, $this); } else { $tokenStream->skipWhitespaces(); while (null !== ($type = $tokenStream->getType())) { switch ($type) { case T_DOC_COMMENT: if (null === $docCommentPosition) { $docCommentPosition = $tokenStream->key(); } case T_WHITESPACE: case T_COMMENT: break; case T_DECLARE: // Intentionally twice call of skipWhitespaces() $tokenStream ->skipWhitespaces() ->findMatchingBracket() ->skipWhitespaces(); break; case T_NAMESPACE: $docCommentPosition = $docCommentPosition ?: -1; break 2; default: $docCommentPosition = $docCommentPosition ?: -1; $this->namespaces[] = new ReflectionFileNamespace($tokenStream, $this->broker, $this); break 2; } $tokenStream->skipWhitespaces(); } while (null !== ($type = $tokenStream->getType())) { if (T_NAMESPACE === $type) { $this->namespaces[] = new ReflectionFileNamespace($tokenStream, $this->broker, $this); } else { $tokenStream->skipWhitespaces(); } } } if (null !== $docCommentPosition && !empty($this->namespaces) && $docCommentPosition === $this->namespaces[0]->getStartPosition()) { $docCommentPosition = null; } $this->docComment = new ReflectionAnnotation($this, null !== $docCommentPosition ? $tokenStream->getTokenValue($docCommentPosition) : null); return $this; } } PHP-Token-Reflection-1.4.0/TokenReflection/ReflectionFileNamespace.php000066400000000000000000000265621237045466400256520ustar00rootroot00000000000000classes; } /** * Returns constant reflections. * * @return array */ public function getConstants() { return $this->constants; } /** * Returns function reflections. * * @return array */ public function getFunctions() { return $this->functions; } /** * Returns all imported namespaces and aliases. * * @return array */ public function getNamespaceAliases() { return $this->aliases; } /** * Processes the parent reflection object. * * @param \TokenReflection\IReflection $parent Parent reflection object * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionElement * @throws \TokenReflection\Exception\ParseException If an invalid parent reflection object was provided. */ protected function processParent(IReflection $parent, Stream $tokenStream) { if (!$parent instanceof ReflectionFile) { throw new Exception\ParseException($this, $tokenStream, 'The parent object has to be an instance of TokenReflection\ReflectionFile.', Exception\ParseException::INVALID_PARENT); } return parent::processParent($parent, $tokenStream); } /** * Parses reflected element metadata from the token stream. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @param \TokenReflection\IReflection $parent Parent reflection object * @return \TokenReflection\ReflectionFileNamespace */ protected function parse(Stream $tokenStream, IReflection $parent) { return $this->parseName($tokenStream); } /** * Find the appropriate docblock. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @param \TokenReflection\IReflection $parent Parent reflection * @return \TokenReflection\ReflectionElement */ protected function parseDocComment(Stream $tokenStream, IReflection $parent) { if (!$tokenStream->is(T_NAMESPACE)) { $this->docComment = new ReflectionAnnotation($this); return $this; } else { return parent::parseDocComment($tokenStream, $parent); } } /** * Parses the namespace name. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionFileNamespace * @throws \TokenReflection\Exception\ParseException If the namespace name could not be determined. */ protected function parseName(Stream $tokenStream) { if (!$tokenStream->is(T_NAMESPACE)) { $this->name = ReflectionNamespace::NO_NAMESPACE_NAME; return $this; } $tokenStream->skipWhitespaces(); $name = ''; // Iterate over the token stream while (true) { switch ($tokenStream->getType()) { // If the current token is a T_STRING, it is a part of the namespace name case T_STRING: case T_NS_SEPARATOR: $name .= $tokenStream->getTokenValue(); break; default: // Stop iterating when other token than string or ns separator found break 2; } $tokenStream->skipWhitespaces(true); } $name = ltrim($name, '\\'); if (empty($name)) { $this->name = ReflectionNamespace::NO_NAMESPACE_NAME; } else { $this->name = $name; } if (!$tokenStream->is(';') && !$tokenStream->is('{')) { throw new Exception\ParseException($this, $tokenStream, 'Invalid namespace name end, expecting ";" or "{".', Exception\ParseException::UNEXPECTED_TOKEN); } $tokenStream->skipWhitespaces(); return $this; } /** * Parses child reflection objects from the token stream. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @param \TokenReflection\IReflection $parent Parent reflection object * @return \TokenReflection\ReflectionFileNamespace * @throws \TokenReflection\Exception\ParseException If child elements could not be parsed. */ protected function parseChildren(Stream $tokenStream, IReflection $parent) { static $skipped = array(T_WHITESPACE => true, T_COMMENT => true, T_DOC_COMMENT => true); $depth = 0; $firstChild = null; while (true) { switch ($tokenStream->getType()) { case T_USE: while (true) { $namespaceName = ''; $alias = null; $tokenStream->skipWhitespaces(true); while (true) { switch ($tokenStream->getType()) { case T_STRING: case T_NS_SEPARATOR: $namespaceName .= $tokenStream->getTokenValue(); break; default: break 2; } $tokenStream->skipWhitespaces(true); } $namespaceName = ltrim($namespaceName, '\\'); if (empty($namespaceName)) { throw new Exception\ParseException($this, $tokenStream, 'Imported namespace name could not be determined.', Exception\ParseException::LOGICAL_ERROR); } elseif ('\\' === substr($namespaceName, -1)) { throw new Exception\ParseException($this, $tokenStream, sprintf('Invalid namespace name "%s".', $namespaceName), Exception\ParseException::LOGICAL_ERROR); } if ($tokenStream->is(T_AS)) { // Alias defined $tokenStream->skipWhitespaces(true); if (!$tokenStream->is(T_STRING)) { throw new Exception\ParseException($this, $tokenStream, sprintf('The imported namespace "%s" seems aliased but the alias name could not be determined.', $namespaceName), Exception\ParseException::LOGICAL_ERROR); } $alias = $tokenStream->getTokenValue(); $tokenStream->skipWhitespaces(true); } else { // No explicit alias if (false !== ($pos = strrpos($namespaceName, '\\'))) { $alias = substr($namespaceName, $pos + 1); } else { $alias = $namespaceName; } } if (isset($this->aliases[$alias])) { throw new Exception\ParseException($this, $tokenStream, sprintf('Namespace alias "%s" already defined.', $alias), Exception\ParseException::LOGICAL_ERROR); } $this->aliases[$alias] = $namespaceName; $type = $tokenStream->getType(); if (';' === $type) { $tokenStream->skipWhitespaces(); break 2; } elseif (',' === $type) { // Next namespace in the current "use" definition continue; } throw new Exception\ParseException($this, $tokenStream, 'Unexpected token found.', Exception\ParseException::UNEXPECTED_TOKEN); } case T_COMMENT: case T_DOC_COMMENT: $docblock = $tokenStream->getTokenValue(); if (preg_match('~^' . preg_quote(self::DOCBLOCK_TEMPLATE_START, '~') . '~', $docblock)) { array_unshift($this->docblockTemplates, new ReflectionAnnotation($this, $docblock)); } elseif (self::DOCBLOCK_TEMPLATE_END === $docblock) { array_shift($this->docblockTemplates); } $tokenStream->next(); break; case '{': $tokenStream->next(); $depth++; break; case '}': if (0 === $depth--) { break 2; } $tokenStream->next(); break; case null: case T_NAMESPACE: break 2; case T_ABSTRACT: case T_FINAL: case T_CLASS: case T_TRAIT: case T_INTERFACE: $class = new ReflectionClass($tokenStream, $this->getBroker(), $this); $firstChild = $firstChild ?: $class; $className = $class->getName(); if (isset($this->classes[$className])) { if (!$this->classes[$className] instanceof Invalid\ReflectionClass) { $this->classes[$className] = new Invalid\ReflectionClass($className, $this->classes[$className]->getFileName(), $this->getBroker()); } if (!$this->classes[$className]->hasReasons()) { $this->classes[$className]->addReason(new Exception\ParseException( $this, $tokenStream, sprintf('Class %s is defined multiple times in the file.', $className), Exception\ParseException::ALREADY_EXISTS )); } } else { $this->classes[$className] = $class; } $tokenStream->next(); break; case T_CONST: $tokenStream->skipWhitespaces(true); do { $constant = new ReflectionConstant($tokenStream, $this->getBroker(), $this); $firstChild = $firstChild ?: $constant; $constantName = $constant->getName(); if (isset($this->constants[$constantName])) { if (!$this->constants[$constantName] instanceof Invalid\ReflectionConstant) { $this->constants[$constantName] = new Invalid\ReflectionConstant($constantName, $this->constants[$constantName]->getFileName(), $this->getBroker()); } if (!$this->constants[$constantName]->hasReasons()) { $this->constants[$constantName]->addReason(new Exception\ParseException( $this, $tokenStream, sprintf('Constant %s is defined multiple times in the file.', $constantName), Exception\ParseException::ALREADY_EXISTS )); } } else { $this->constants[$constantName] = $constant; } if ($tokenStream->is(',')) { $tokenStream->skipWhitespaces(true); } else { $tokenStream->next(); } } while ($tokenStream->is(T_STRING)); break; case T_FUNCTION: $position = $tokenStream->key() + 1; while (isset($skipped[$type = $tokenStream->getType($position)])) { $position++; } if ('(' === $type) { // Skipping anonymous functions $tokenStream ->seek($position) ->findMatchingBracket() ->skipWhiteSpaces(true); if ($tokenStream->is(T_USE)) { $tokenStream ->skipWhitespaces(true) ->findMatchingBracket() ->skipWhitespaces(true); } $tokenStream ->findMatchingBracket() ->next(); continue; } $function = new ReflectionFunction($tokenStream, $this->getBroker(), $this); $firstChild = $firstChild ?: $function; $functionName = $function->getName(); if (isset($this->functions[$functionName])) { if (!$this->functions[$functionName] instanceof Invalid\ReflectionFunction) { $this->functions[$functionName] = new Invalid\ReflectionFunction($functionName, $this->functions[$functionName]->getFileName(), $this->getBroker()); } if (!$this->functions[$functionName]->hasReasons()) { $this->functions[$functionName]->addReason(new Exception\ParseException( $this, $tokenStream, sprintf('Function %s is defined multiple times in the file.', $functionName), Exception\ParseException::ALREADY_EXISTS )); } } else { $this->functions[$functionName] = $function; } $tokenStream->next(); break; default: $tokenStream->next(); break; } } if ($firstChild) { $this->startPosition = min($this->startPosition, $firstChild->getStartPosition()); } return $this; } } PHP-Token-Reflection-1.4.0/TokenReflection/ReflectionFunction.php000066400000000000000000000120011237045466400247220ustar00rootroot00000000000000hasAnnotation('disabled'); } /** * Returns the string representation of the reflection object. * * @return string */ public function __toString() { $parameters = ''; if ($this->getNumberOfParameters() > 0) { $buffer = ''; foreach ($this->getParameters() as $parameter) { $buffer .= "\n " . $parameter->__toString(); } $parameters = sprintf( "\n\n - Parameters [%d] {%s\n }", $this->getNumberOfParameters(), $buffer ); } return sprintf( "%sFunction [ function %s%s ] {\n @@ %s %d - %d%s\n}\n", $this->getDocComment() ? $this->getDocComment() . "\n" : '', $this->returnsReference() ? '&' : '', $this->getName(), $this->getFileName(), $this->getStartLine(), $this->getEndLine(), $parameters ); } /** * Exports a reflected object. * * @param \TokenReflection\Broker $broker Broker instance * @param string $function Function name * @param boolean $return Return the export instead of outputting it * @return string|null * @throws \TokenReflection\Exception\RuntimeException If requested parameter doesn't exist. */ public static function export(Broker $broker, $function, $return = false) { $functionName = $function; $function = $broker->getFunction($functionName); if (null === $function) { throw new Exception\RuntimeException(sprintf('Function %s() does not exist.', $functionName), Exception\RuntimeException::DOES_NOT_EXIST); } if ($return) { return $function->__toString(); } echo $function->__toString(); } /** * Calls the function. * * @return mixed */ public function invoke() { return $this->invokeArgs(func_get_args()); } /** * Calls the function. * * @param array $args Function parameter values * @return mixed * @throws \TokenReflection\Exception\RuntimeException If the required function does not exist. */ public function invokeArgs(array $args = array()) { if (!function_exists($this->getName())) { throw new Exception\RuntimeException('Could not invoke function; function is not defined.', Exception\RuntimeException::DOES_NOT_EXIST, $this); } return call_user_func_array($this->getName(), $args); } /** * Returns imported namespaces and aliases from the declaring namespace. * * @return array */ public function getNamespaceAliases() { return $this->aliases; } /** * Returns the function/method as closure. * * @return \Closure */ public function getClosure() { if (!function_exists($this->getName())) { throw new Exception\RuntimeException('Could not invoke function; function is not defined.', Exception\RuntimeException::DOES_NOT_EXIST, $this); } $that = $this; return function() use ($that) { return $that->invokeArgs(func_get_args()); }; } /** * Returns the closure scope class. * * @return null */ public function getClosureScopeClass() { return null; } /** * Returns if the function definition is valid. * * @return boolean */ public function isValid() { return true; } /** * Processes the parent reflection object. * * @param \TokenReflection\IReflection $parent Parent reflection object * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionElement * @throws \TokenReflection\Exception\ParseException If an invalid parent reflection object was provided. */ protected function processParent(IReflection $parent, Stream $tokenStream) { if (!$parent instanceof ReflectionFileNamespace) { throw new Exception\ParseException($this, $tokenStream, 'The parent object has to be an instance of TokenReflection\ReflectionFileNamespace.', Exception\ParseException::INVALID_PARENT); } $this->namespaceName = $parent->getName(); $this->aliases = $parent->getNamespaceAliases(); return parent::processParent($parent, $tokenStream); } /** * Parses reflected element metadata from the token stream. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @param \TokenReflection\IReflection $parent Parent reflection object * @return \TokenReflection\ReflectionFunction */ protected function parse(Stream $tokenStream, IReflection $parent) { return $this ->parseReturnsReference($tokenStream) ->parseName($tokenStream); } } PHP-Token-Reflection-1.4.0/TokenReflection/ReflectionFunctionBase.php000066400000000000000000000256271237045466400255370ustar00rootroot00000000000000namespaceName && ReflectionNamespace::NO_NAMESPACE_NAME !== $this->namespaceName) { return $this->namespaceName . '\\' . $this->name; } return $this->name; } /** * Returns the unqualified name (UQN). * * @return string */ public function getShortName() { return $this->name; } /** * Returns the namespace name. * * @return string */ public function getNamespaceName() { return null === $this->namespaceName || $this->namespaceName === ReflectionNamespace::NO_NAMESPACE_NAME ? '' : $this->namespaceName; } /** * Returns if the function/method is defined within a namespace. * * @return boolean */ public function inNamespace() { return '' !== $this->getNamespaceName(); } /** * Returns if the function/method is a closure. * * @return boolean */ public function isClosure() { return false; } /** * Returns this pointer bound to closure. * * @return null */ public function getClosureThis() { return null; } /** * Returns the closure scope class. * * @return string|null */ public function getClosureScopeClass() { return null; } /** * Returns if the function/method returns its value as reference. * * @return boolean */ public function returnsReference() { return $this->returnsReference; } /** * Returns a particular function/method parameter. * * @param integer|string $parameter Parameter name or position * @return \TokenReflection\ReflectionParameter * @throws \TokenReflection\Exception\RuntimeException If there is no parameter of the given name. * @throws \TokenReflection\Exception\RuntimeException If there is no parameter at the given position. */ public function getParameter($parameter) { if (is_numeric($parameter)) { if (!isset($this->parameters[$parameter])) { throw new Exception\RuntimeException(sprintf('There is no parameter at position "%d".', $parameter), Exception\RuntimeException::DOES_NOT_EXIST, $this); } return $this->parameters[$parameter]; } else { foreach ($this->parameters as $reflection) { if ($reflection->getName() === $parameter) { return $reflection; } } throw new Exception\RuntimeException(sprintf('There is no parameter "%s".', $parameter), Exception\RuntimeException::DOES_NOT_EXIST, $this); } } /** * Returns parameters. * * @return array */ public function getParameters() { return $this->parameters; } /** * Returns the number of parameters. * * @return integer */ public function getNumberOfParameters() { return count($this->parameters); } /** * Returns the number of required parameters. * * @return integer */ public function getNumberOfRequiredParameters() { $count = 0; array_walk($this->parameters, function(ReflectionParameter $parameter) use (&$count) { if (!$parameter->isOptional()) { $count++; } }); return $count; } /** * Returns static variables. * * @return array */ public function getStaticVariables() { if (empty($this->staticVariables) && !empty($this->staticVariablesDefinition)) { foreach ($this->staticVariablesDefinition as $variableName => $variableDefinition) { $this->staticVariables[$variableName] = Resolver::getValueDefinition($variableDefinition, $this); } } return $this->staticVariables; } /** * Returns an element pretty (docblock compatible) name. * * @return string */ public function getPrettyName() { return $this->name . '()'; } /** * Creates aliases to parameters. * * @throws \TokenReflection\Exception\RuntimeException When called on a ReflectionFunction instance. */ protected final function aliasParameters() { if (!$this instanceof ReflectionMethod) { throw new Exception\RuntimeException('Only method parameters can be aliased.', Exception\RuntimeException::UNSUPPORTED, $this); } foreach ($this->parameters as $index => $parameter) { $this->parameters[$index] = $parameter->alias($this); } } /** * Parses if the function/method returns its value as reference. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionFunctionBase * @throws \TokenReflection\Exception\ParseException If could not be determined if the function\method returns its value by reference. */ final protected function parseReturnsReference(Stream $tokenStream) { if (!$tokenStream->is(T_FUNCTION)) { throw new Exception\ParseException($this, $tokenStream, 'Could not find the function keyword.', Exception\ParseException::UNEXPECTED_TOKEN); } $tokenStream->skipWhitespaces(true); $type = $tokenStream->getType(); if ('&' === $type) { $this->returnsReference = true; $tokenStream->skipWhitespaces(true); } elseif (T_STRING !== $type) { throw new Exception\ParseException($this, $tokenStream, 'Unexpected token found.', Exception\ParseException::UNEXPECTED_TOKEN); } return $this; } /** * Parses the function/method name. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionMethod * @throws \TokenReflection\Exception\ParseException If the class name could not be determined. */ final protected function parseName(Stream $tokenStream) { $this->name = $tokenStream->getTokenValue(); $tokenStream->skipWhitespaces(true); return $this; } /** * Parses child reflection objects from the token stream. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @param \TokenReflection\IReflection $parent Parent reflection object * @return \TokenReflection\ReflectionElement */ final protected function parseChildren(Stream $tokenStream, IReflection $parent) { return $this ->parseParameters($tokenStream) ->parseStaticVariables($tokenStream); } /** * Parses function/method parameters. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionFunctionBase * @throws \TokenReflection\Exception\ParseException If parameters could not be parsed. */ final protected function parseParameters(Stream $tokenStream) { if (!$tokenStream->is('(')) { throw new Exception\ParseException($this, $tokenStream, 'Could find the start token.', Exception\ParseException::UNEXPECTED_TOKEN); } static $accepted = array(T_NS_SEPARATOR => true, T_STRING => true, T_ARRAY => true, T_CALLABLE => true, T_VARIABLE => true, '&' => true); $tokenStream->skipWhitespaces(true); while (null !== ($type = $tokenStream->getType()) && ')' !== $type) { if (isset($accepted[$type])) { $parameter = new ReflectionParameter($tokenStream, $this->getBroker(), $this); $this->parameters[] = $parameter; } if ($tokenStream->is(')')) { break; } $tokenStream->skipWhitespaces(true); } $tokenStream->skipWhitespaces(); return $this; } /** * Parses static variables. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionFunctionBase * @throws \TokenReflection\Exception\ParseException If static variables could not be parsed. */ final protected function parseStaticVariables(Stream $tokenStream) { $type = $tokenStream->getType(); if ('{' === $type) { if ($this->getBroker()->isOptionSet(Broker::OPTION_PARSE_FUNCTION_BODY)) { $tokenStream->skipWhitespaces(true); while ('}' !== ($type = $tokenStream->getType())) { switch ($type) { case T_STATIC: $type = $tokenStream->skipWhitespaces(true)->getType(); if (T_VARIABLE !== $type) { // Late static binding break; } while (T_VARIABLE === $type) { $variableName = $tokenStream->getTokenValue(); $variableDefinition = array(); $type = $tokenStream->skipWhitespaces(true)->getType(); if ('=' === $type) { $type = $tokenStream->skipWhitespaces(true)->getType(); $level = 0; while ($tokenStream->valid()) { switch ($type) { case '(': case '[': case '{': case T_CURLY_OPEN: case T_DOLLAR_OPEN_CURLY_BRACES: $level++; break; case ')': case ']': case '}': $level--; break; case ';': case ',': if (0 === $level) { break 2; } default: break; } $variableDefinition[] = $tokenStream->current(); $type = $tokenStream->skipWhitespaces(true)->getType(); } if (!$tokenStream->valid()) { throw new Exception\ParseException($this, $tokenStream, 'Invalid end of token stream.', Exception\ParseException::READ_BEYOND_EOS); } } $this->staticVariablesDefinition[substr($variableName, 1)] = $variableDefinition; if (',' === $type) { $type = $tokenStream->skipWhitespaces(true)->getType(); } else { break; } } break; case T_FUNCTION: // Anonymous function -> skip to its end if (!$tokenStream->find('{')) { throw new Exception\ParseException($this, $tokenStream, 'Could not find beginning of the anonymous function.', Exception\ParseException::UNEXPECTED_TOKEN); } // Break missing intentionally case '{': case '[': case '(': case T_CURLY_OPEN: case T_DOLLAR_OPEN_CURLY_BRACES: $tokenStream->findMatchingBracket()->skipWhitespaces(true); break; default: $tokenStream->skipWhitespaces(); break; } } } else { $tokenStream->findMatchingBracket(); } } elseif (';' !== $type) { throw new Exception\ParseException($this, $tokenStream, 'Unexpected token found.', Exception\ParseException::UNEXPECTED_TOKEN); } return $this; } } PHP-Token-Reflection-1.4.0/TokenReflection/ReflectionMethod.php000066400000000000000000000501251237045466400243660ustar00rootroot00000000000000declaringClassName ? null : $this->getBroker()->getClass($this->declaringClassName); } /** * Returns the declaring class name. * * @return string|null */ public function getDeclaringClassName() { return $this->declaringClassName; } /** * Returns method modifiers. * * @return integer */ public function getModifiers() { if (!$this->modifiersComplete && !($this->modifiers & (self::ACCESS_LEVEL_CHANGED | self::IS_IMPLEMENTED_ABSTRACT))) { $declaringClass = $this->getDeclaringClass(); $parentClass = $declaringClass->getParentClass(); if (false !== $parentClass && $parentClass->hasMethod($this->name)) { $parentClassMethod = $parentClass->getMethod($this->name); // Access level changed if (($this->isPublic() || $this->isProtected()) && $parentClassMethod->is(self::ACCESS_LEVEL_CHANGED | InternalReflectionMethod::IS_PRIVATE)) { $this->modifiers |= self::ACCESS_LEVEL_CHANGED; } // Implemented abstract if ($parentClassMethod->isAbstract() && !$this->isAbstract()) { $this->modifiers |= self::IS_IMPLEMENTED_ABSTRACT; } } else { // Check if it is an implementation of an interface method foreach ($declaringClass->getInterfaces() as $interface) { if ($interface->hasOwnMethod($this->name)) { $this->modifiers |= self::IS_IMPLEMENTED_ABSTRACT; break; } } } // Set if modifiers definition is complete $this->modifiersComplete = $this->isComplete() || (($this->modifiers & self::IS_IMPLEMENTED_ABSTRACT) && ($this->modifiers & self::ACCESS_LEVEL_CHANGED)); } return $this->modifiers; } /** * Returns if the method is abstract. * * @return boolean */ public function isAbstract() { return (bool) ($this->modifiers & InternalReflectionMethod::IS_ABSTRACT); } /** * Returns if the method is final. * * @return boolean */ public function isFinal() { return (bool) ($this->modifiers & InternalReflectionMethod::IS_FINAL); } /** * Returns if the method is private. * * @return boolean */ public function isPrivate() { return (bool) ($this->modifiers & InternalReflectionMethod::IS_PRIVATE); } /** * Returns if the method is protected. * * @return boolean */ public function isProtected() { return (bool) ($this->modifiers & InternalReflectionMethod::IS_PROTECTED); } /** * Returns if the method is public. * * @return boolean */ public function isPublic() { return (bool) ($this->modifiers & InternalReflectionMethod::IS_PUBLIC); } /** * Returns if the method is static. * * @return boolean */ public function isStatic() { return (bool) ($this->modifiers & InternalReflectionMethod::IS_STATIC); } /** * Shortcut for isPublic(), ... methods that allows or-ed modifiers. * * The {@see getModifiers()} method is called only when really necessary making this * a more efficient way of doing * * if ($method->getModifiers() & $filter) { * ... * } * * * @param integer $filter Filter * @return boolean */ public function is($filter = null) { // See self::ACCESS_LEVEL_CHANGED | self::IS_IMPLEMENTED_ABSTRACT static $computedModifiers = 0x808; if (null === $filter || ($this->modifiers & $filter)) { return true; } elseif (($filter & $computedModifiers) && !$this->modifiersComplete) { return (bool) ($this->getModifiers() & $filter); } return false; } /** * Returns if the method is a constructor. * * @return boolean */ public function isConstructor() { return (bool) ($this->modifiers & self::IS_CONSTRUCTOR); } /** * Returns if the method is a destructor. * * @return boolean */ public function isDestructor() { return (bool) ($this->modifiers & self::IS_DESTRUCTOR); } /** * Returns the method prototype. * * @return \TokenReflection\ReflectionMethod * @throws \TokenReflection\Exception\RuntimeException If the method has no prototype. */ public function getPrototype() { if (null === $this->prototype) { $prototype = null; $declaring = $this->getDeclaringClass(); if (($parent = $declaring->getParentClass()) && $parent->hasMethod($this->name)) { $method = $parent->getMethod($this->name); if (!$method->isPrivate()) { try { $prototype = $method->getPrototype(); } catch (Exception\RuntimeException $e) { $prototype = $method; } } } if (null === $prototype) { foreach ($declaring->getOwnInterfaces() as $interface) { if ($interface->hasMethod($this->name)) { $prototype = $interface->getMethod($this->name); break; } } } $this->prototype = $prototype ?: ($this->isComplete() ? false : null); } if (empty($this->prototype)) { throw new Exception\RuntimeException('Method has no prototype.', Exception\RuntimeException::DOES_NOT_EXIST, $this); } return $this->prototype; } /** * Returns an element pretty (docblock compatible) name. * * @return string */ public function getPrettyName() { return sprintf('%s::%s', $this->declaringClassName ?: $this->declaringTraitName, parent::getPrettyName()); } /** * Returns the string representation of the reflection object. * * @return string */ public function __toString() { $internal = ''; $overwrite = ''; $prototype = ''; $declaringClassParent = $this->getDeclaringClass()->getParentClass(); try { $prototype = ', prototype ' . $this->getPrototype()->getDeclaringClassName(); } catch (Exception\RuntimeException $e) { if ($declaringClassParent && $declaringClassParent->isInternal()) { $internal = 'internal:' . $parentClass->getExtensionName(); } } if ($declaringClassParent && $declaringClassParent->hasMethod($this->name)) { $parentMethod = $declaringClassParent->getMethod($this->name); $overwrite = ', overwrites ' . $parentMethod->getDeclaringClassName(); } if ($this->isConstructor()) { $cdtor = ', ctor'; } elseif ($this->isDestructor()) { $cdtor = ', dtor'; } else { $cdtor = ''; } $parameters = ''; if ($this->getNumberOfParameters() > 0) { $buffer = ''; foreach ($this->getParameters() as $parameter) { $buffer .= "\n " . $parameter->__toString(); } $parameters = sprintf( "\n\n - Parameters [%d] {%s\n }", $this->getNumberOfParameters(), $buffer ); } // @todo support inherits return sprintf( "%sMethod [ <%s%s%s%s> %s%s%s%s%s%s method %s%s ] {\n @@ %s %d - %d%s\n}\n", $this->getDocComment() ? $this->getDocComment() . "\n" : '', !empty($internal) ? $internal : 'user', $overwrite, $prototype, $cdtor, $this->isAbstract() ? 'abstract ' : '', $this->isFinal() ? 'final ' : '', $this->isStatic() ? 'static ' : '', $this->isPublic() ? 'public' : '', $this->isPrivate() ? 'private' : '', $this->isProtected() ? 'protected' : '', $this->returnsReference() ? '&' : '', $this->getName(), $this->getFileName(), $this->getStartLine(), $this->getEndLine(), $parameters ); } /** * Exports a reflected object. * * @param \TokenReflection\Broker $broker Broker instance * @param string|object $class Class name or class instance * @param string $method Method name * @param boolean $return Return the export instead of outputting it * @return string|null * @throws \TokenReflection\Exception\RuntimeException If requested parameter doesn't exist. */ public static function export(Broker $broker, $class, $method, $return = false) { $className = is_object($class) ? get_class($class) : $class; $methodName = $method; $class = $broker->getClass($className); if ($class instanceof Invalid\ReflectionClass) { throw new Exception\RuntimeException('Class is invalid.', Exception\RuntimeException::UNSUPPORTED); } elseif ($class instanceof Dummy\ReflectionClass) { throw new Exception\RuntimeException(sprintf('Class %s does not exist.', $className), Exception\RuntimeException::DOES_NOT_EXIST); } $method = $class->getMethod($methodName); if ($return) { return $method->__toString(); } echo $method->__toString(); } /** * Calls the method on an given instance. * * @param object $object Class instance * @param mixed $args * @return mixed */ public function invoke($object, $args) { $params = func_get_args(); return $this->invokeArgs(array_shift($params), $params); } /** * Calls the method on an given object. * * @param object $object Class instance * @param array $args Method parameter values * @return mixed * @throws \TokenReflection\Exception\RuntimeException If it is not possible to invoke the method. */ public function invokeArgs($object, array $args = array()) { $declaringClass = $this->getDeclaringClass(); if (!$declaringClass->isInstance($object)) { throw new Exception\RuntimeException(sprintf('Expected instance of or subclass of "%s".', $this->declaringClassName), Exception\RuntimeException::INVALID_ARGUMENT, $this); } if ($this->isPublic()) { return call_user_func_array(array($object, $this->getName()), $args); } elseif ($this->isAccessible()) { $refClass = new InternalReflectionClass($object); $refMethod = $refClass->getMethod($this->name); $refMethod->setAccessible(true); $value = $refMethod->invokeArgs($object, $args); $refMethod->setAccessible(false); return $value; } throw new Exception\RuntimeException('Only public methods can be invoked.', Exception\RuntimeException::NOT_ACCESSBILE, $this); } /** * Returns if the property is set accessible. * * @return boolean */ public function isAccessible() { return $this->accessible; } /** * Sets a method to be accessible or not. * * @param boolean $accessible */ public function setAccessible($accessible) { $this->accessible = (bool) $accessible; } /** * Returns if the definition is complete. * * Technically returns if the declaring class definition is complete. * * @return boolean */ private function isComplete() { return $this->getDeclaringClass()->isComplete(); } /** * Returns imported namespaces and aliases from the declaring namespace. * * @return array */ public function getNamespaceAliases() { return $this->getDeclaringClass()->getNamespaceAliases(); } /** * Returns the function/method as closure. * * @param object $object Object * @return \Closure */ public function getClosure($object) { $declaringClass = $this->getDeclaringClass(); if (!$declaringClass->isInstance($object)) { throw new Exception\RuntimeException(sprintf('Expected instance of or subclass of "%s".', $this->declaringClassName), Exception\RuntimeException::INVALID_ARGUMENT, $this); } $that = $this; return function() use ($object, $that) { return $that->invokeArgs($object, func_get_args()); }; } /** * Creates a method alias of the given name and access level for the given class. * * @param \TokenReflection\ReflectionClass $parent New parent class * @param string $name New method name * @param integer $accessLevel New access level * @return \TokenReflection\ReflectionMethod * @throws \TokenReflection\Exception\RuntimeException If an invalid method access level was found. */ public function alias(ReflectionClass $parent, $name = null, $accessLevel = null) { static $possibleLevels = array(InternalReflectionMethod::IS_PUBLIC => true, InternalReflectionMethod::IS_PROTECTED => true, InternalReflectionMethod::IS_PRIVATE => true); $method = clone $this; $method->declaringClassName = $parent->getName(); if (null !== $name) { $method->originalName = $this->name; $method->name = $name; } if (null !== $accessLevel) { if (!isset($possibleLevels[$accessLevel])) { throw new Exception\RuntimeException(sprintf('Invalid method access level: "%s".', $accessLevel), Exception\RuntimeException::INVALID_ARGUMENT, $this); } $method->modifiers &= ~(InternalReflectionMethod::IS_PUBLIC | InternalReflectionMethod::IS_PROTECTED | InternalReflectionMethod::IS_PRIVATE); $method->modifiers |= $accessLevel; $method->originalModifiers = $this->getModifiers(); } foreach ($this->parameters as $parameterName => $parameter) { $method->parameters[$parameterName] = $parameter->alias($method); } return $method; } /** * Returns the original name when importing from a trait. * * @return string|null */ public function getOriginalName() { return $this->originalName; } /** * Returns the original method when importing from a trait. * * @return \TokenReflection\IReflectionMethod|null */ public function getOriginal() { return $this->original; } /** * Returns the original modifiers value when importing from a trait. * * @return integer|null */ public function getOriginalModifiers() { return $this->originalModifiers; } /** * Returns the defining trait. * * @return \TokenReflection\IReflectionClass|null */ public function getDeclaringTrait() { return null === $this->declaringTraitName ? null : $this->getBroker()->getClass($this->declaringTraitName); } /** * Returns the declaring trait name. * * @return string|null */ public function getDeclaringTraitName() { return $this->declaringTraitName; } /** * Processes the parent reflection object. * * @param \TokenReflection\IReflection $parent Parent reflection object * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionElement * @throws \TokenReflection\Exception\ParseException If an invalid parent reflection object was provided. */ protected function processParent(IReflection $parent, Stream $tokenStream) { if (!$parent instanceof ReflectionClass) { throw new Exception\ParseException($this, $tokenStream, 'The parent object has to be an instance of TokenReflection\ReflectionClass.', Exception\ParseException::INVALID_PARENT); } $this->declaringClassName = $parent->getName(); if ($parent->isTrait()) { $this->declaringTraitName = $parent->getName(); } return parent::processParent($parent, $tokenStream); } /** * Parses reflected element metadata from the token stream. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @param \TokenReflection\IReflection $parent Parent reflection object * @return \TokenReflection\ReflectionMethod * @throws \TokenReflection\Exception\Parse If the class could not be parsed. */ protected function parse(Stream $tokenStream, IReflection $parent) { return $this ->parseBaseModifiers($tokenStream) ->parseReturnsReference($tokenStream) ->parseName($tokenStream) ->parseInternalModifiers($parent); } /** * Parses base method modifiers (abstract, final, public, ...). * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionMethod */ private function parseBaseModifiers(Stream $tokenStream) { while (true) { switch ($tokenStream->getType()) { case T_ABSTRACT: $this->modifiers |= InternalReflectionMethod::IS_ABSTRACT; break; case T_FINAL: $this->modifiers |= InternalReflectionMethod::IS_FINAL; break; case T_PUBLIC: $this->modifiers |= InternalReflectionMethod::IS_PUBLIC; break; case T_PRIVATE: $this->modifiers |= InternalReflectionMethod::IS_PRIVATE; break; case T_PROTECTED: $this->modifiers |= InternalReflectionMethod::IS_PROTECTED; break; case T_STATIC: $this->modifiers |= InternalReflectionMethod::IS_STATIC; break; case T_FUNCTION: case null: break 2; default: break; } $tokenStream->skipWhitespaces(); } if (!($this->modifiers & (InternalReflectionMethod::IS_PRIVATE | InternalReflectionMethod::IS_PROTECTED))) { $this->modifiers |= InternalReflectionMethod::IS_PUBLIC; } return $this; } /** * Parses internal PHP method modifiers (abstract, final, public, ...). * * @param \TokenReflection\ReflectionClass $class Parent class * @return \TokenReflection\ReflectionMethod */ private function parseInternalModifiers(ReflectionClass $class) { $name = strtolower($this->name); // In PHP 5.3.3+ the ctor can be named only __construct in namespaced classes if ('__construct' === $name || ((!$class->inNamespace() || PHP_VERSION_ID < 50303) && strtolower($class->getShortName()) === $name)) { $this->modifiers |= self::IS_CONSTRUCTOR; } elseif ('__destruct' === $name) { $this->modifiers |= self::IS_DESTRUCTOR; } elseif ('__clone' === $name) { $this->modifiers |= self::IS_CLONE; } if ($class->isInterface()) { $this->modifiers |= InternalReflectionMethod::IS_ABSTRACT; } else { // Can be called statically, see http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/Zend/zend_API.c?revision=309853&view=markup#l1795 static $notAllowed = array('__clone' => true, '__tostring' => true, '__get' => true, '__set' => true, '__isset' => true, '__unset' => true); if (!$this->isStatic() && !$this->isConstructor() && !$this->isDestructor() && !isset($notAllowed[$name])) { $this->modifiers |= self::IS_ALLOWED_STATIC; } } return $this; } } PHP-Token-Reflection-1.4.0/TokenReflection/ReflectionNamespace.php000066400000000000000000000327431237045466400250500ustar00rootroot00000000000000name = $name; $this->broker = $broker; } /** * Returns the name. * * @return string */ public function getName() { return $this->name; } /** * Returns if the namespace is internal. * * Always false. * * @return boolean */ public function isInternal() { return false; } /** * Returns if the namespace is user defined. * * Always true. * * @return boolean */ public function isUserDefined() { return true; } /** * Returns if the current reflection comes from a tokenized source. * * @return boolean */ public function isTokenized() { return true; } /** * Returns if the namespace contains a class of the given name. * * @param string $className Class name * @return boolean */ public function hasClass($className) { $className = ltrim($className, '\\'); if (false === strpos($className, '\\') && self::NO_NAMESPACE_NAME !== $this->getName()) { $className = $this->getName() . '\\' . $className; } return isset($this->classes[$className]); } /** * Return a class reflection. * * @param string $className Class name * @return \TokenReflection\ReflectionClass * @throws \TokenReflection\Exception\RuntimeException If the requested class reflection does not exist. */ public function getClass($className) { $className = ltrim($className, '\\'); if (false === strpos($className, '\\') && self::NO_NAMESPACE_NAME !== $this->getName()) { $className = $this->getName() . '\\' . $className; } if (!isset($this->classes[$className])) { throw new Exception\RuntimeException(sprintf('Class "%s" does not exist.', $className), Exception\RuntimeException::DOES_NOT_EXIST, $this); } return $this->classes[$className]; } /** * Returns class reflections. * * @return array */ public function getClasses() { return $this->classes; } /** * Returns class names (FQN). * * @return array */ public function getClassNames() { return array_keys($this->classes); } /** * Returns class unqualified names (UQN). * * @return array */ public function getClassShortNames() { return array_map(function(IReflectionClass $class) { return $class->getShortName(); }, $this->classes); } /** * Returns if the namespace contains a constant of the given name. * * @param string $constantName Constant name * @return boolean */ public function hasConstant($constantName) { $constantName = ltrim($constantName, '\\'); if (false === strpos($constantName, '\\') && self::NO_NAMESPACE_NAME !== $this->getName()) { $constantName = $this->getName() . '\\' . $constantName; } return isset($this->constants[$constantName]); } /** * Returns a constant reflection. * * @param string $constantName Constant name * @return \TokenReflection\ReflectionConstant * @throws \TokenReflection\Exception\RuntimeException If the required constant does not exist. */ public function getConstant($constantName) { $constantName = ltrim($constantName, '\\'); if (false === strpos($constantName, '\\') && self::NO_NAMESPACE_NAME !== $this->getName()) { $constantName = $this->getName() . '\\' . $constantName; } if (!isset($this->constants[$constantName])) { throw new Exception\RuntimeException(sprintf('Constant "%s" does not exist.', $constantName), Exception\RuntimeException::DOES_NOT_EXIST, $this); } return $this->constants[$constantName]; } /** * Returns constant reflections. * * @return array */ public function getConstants() { return $this->constants; } /** * Returns constant names (FQN). * * @return array */ public function getConstantNames() { return array_keys($this->constants); } /** * Returns constant unqualified names (UQN). * * @return array */ public function getConstantShortNames() { return array_map(function(IReflectionConstant $constant) { return $constant->getShortName(); }, $this->constants); } /** * Returns if the namespace contains a function of the given name. * * @param string $functionName Function name * @return boolean */ public function hasFunction($functionName) { $functionName = ltrim($functionName, '\\'); if (false === strpos($functionName, '\\') && self::NO_NAMESPACE_NAME !== $this->getName()) { $functionName = $this->getName() . '\\' . $functionName; } return isset($this->functions[$functionName]); } /** * Returns a function reflection. * * @param string $functionName Function name * @return \TokenReflection\ReflectionFunction * @throws \TokenReflection\Exception\RuntimeException If the required function does not exist. */ public function getFunction($functionName) { $functionName = ltrim($functionName, '\\'); if (false === strpos($functionName, '\\') && self::NO_NAMESPACE_NAME !== $this->getName()) { $functionName = $this->getName() . '\\' . $functionName; } if (!isset($this->functions[$functionName])) { throw new Exception\RuntimeException(sprintf('Function "%s" does not exist.', $functionName), Exception\RuntimeException::DOES_NOT_EXIST, $this); } return $this->functions[$functionName]; } /** * Returns function reflections. * * @return array */ public function getFunctions() { return $this->functions; } /** * Returns function names (FQN). * * @return array */ public function getFunctionNames() { return array_keys($this->functions); } /** * Returns function unqualified names (UQN). * * @return array */ public function getFunctionShortNames() { return array_map(function(IReflectionFunction $function) { return $function->getShortName(); }, $this->functions); } /** * Returns an element pretty (docblock compatible) name. * * @return string */ public function getPrettyName() { return $this->name; } /** * Returns the string representation of the reflection object. * * @return string */ public function __toString() { $buffer = ''; $count = 0; foreach ($this->getClasses() as $class) { $string = "\n " . trim(str_replace("\n", "\n ", $class->__toString()), ' '); $string = str_replace(" \n - Parameters", "\n - Parameters", $string); $buffer .= $string; $count++; } $classes = sprintf("\n\n - Classes [%d] {\n%s }", $count, ltrim($buffer, "\n")); $buffer = ''; $count = 0; foreach ($this->getConstants() as $constant) { $buffer .= ' ' . $constant->__toString(); $count++; } $constants = sprintf("\n\n - Constants [%d] {\n%s }", $count, $buffer); $buffer = ''; $count = 0; foreach ($this->getFunctions() as $function) { $string = "\n " . trim(str_replace("\n", "\n ", $function->__toString()), ' '); $string = str_replace(" \n - Parameters", "\n - Parameters", $string); $buffer .= $string; $count++; } $functions = sprintf("\n\n - Functions [%d] {\n%s }", $count, ltrim($buffer, "\n")); return sprintf( "Namespace [ namespace %s ] { %s%s%s\n}\n", $this->getName(), $classes, $constants, $functions ); } /** * Exports a reflected object. * * @param \TokenReflection\Broker $broker Broker instance * @param string $namespace Namespace name * @param boolean $return Return the export instead of outputting it * @return string|null * @throws \TokenReflection\Exception\RuntimeException If requested parameter doesn't exist. */ public static function export(Broker $broker, $namespace, $return = false) { $namespaceName = $namespace; $namespace = $broker->getNamespace($namespaceName); if (null === $namespace) { throw new Exception\RuntimeException(sprintf('Namespace %s does not exist.', $namespaceName), Exception\RuntimeException::DOES_NOT_EXIST); } if ($return) { return $namespace->__toString(); } echo $namespace->__toString(); } /** * Adds a namespace part from a file. * * @param \TokenReflection\ReflectionFileNamespace $namespace Namespace part * @return \TokenReflection\ReflectionNamespace * @throws \TokenReflection\Exception\FileProcessingException If one of classes, functions or constants form the namespace are already defined */ public function addFileNamespace(ReflectionFileNamespace $namespace) { $errors = array(); foreach ($namespace->getClasses() as $className => $reflection) { if ($reflection instanceof Invalid\ReflectionClass) { $errors = array_merge($errors, $reflection->getReasons()); } if (isset($this->classes[$className])) { if (!$this->classes[$className] instanceof Invalid\ReflectionClass) { $this->classes[$className] = new Invalid\ReflectionClass($className, $this->classes[$className]->getFileName(), $this->getBroker()); } $error = new Exception\RuntimeException( sprintf('Class %s was redeclared (previously declared in file %s).', $className, $this->classes[$className]->getFileName()), Exception\RuntimeException::ALREADY_EXISTS, $reflection ); $errors[] = $error; $this->classes[$className]->addReason($error); if ($reflection instanceof Invalid\ReflectionClass) { foreach ($reflection->getReasons() as $reason) { $this->classes[$className]->addReason($reason); } } } else { $this->classes[$className] = $reflection; } } foreach ($namespace->getFunctions() as $functionName => $reflection) { if ($reflection instanceof Invalid\ReflectionFunction) { $errors = array_merge($errors, $reflection->getReasons()); } if (isset($this->functions[$functionName])) { if (!$this->functions[$functionName] instanceof Invalid\ReflectionFunction) { $this->functions[$functionName] = new Invalid\ReflectionFunction($functionName, $this->functions[$functionName]->getFileName(), $this->getBroker()); } $error = new Exception\RuntimeException( sprintf('Function %s was redeclared (previousy declared in file %s).', $functionName, $this->functions[$functionName]->getFileName()), Exception\RuntimeException::ALREADY_EXISTS, $reflection ); $errors[] = $error; $this->functions[$functionName]->addReason($error); if ($reflection instanceof Invalid\ReflectionFunction) { foreach ($reflection->getReasons() as $reason) { $this->functions[$functionName]->addReason($reason); } } } else { $this->functions[$functionName] = $reflection; } } foreach ($namespace->getConstants() as $constantName => $reflection) { if ($reflection instanceof Invalid\ReflectionConstant) { $errors = array_merge($errors, $reflection->getReasons()); } if (isset($this->constants[$constantName])) { if (!$this->constants[$constantName] instanceof Invalid\ReflectionConstant) { $this->constants[$constantName] = new Invalid\ReflectionConstant($constantName, $this->constants[$constantName]->getFileName(), $this->getBroker()); } $error = new Exception\RuntimeException( sprintf('Constant %s was redeclared (previuosly declared in file %s).', $constantName, $this->constants[$constantName]->getFileName()), Exception\RuntimeException::ALREADY_EXISTS, $reflection ); $errors[] = $error; $this->constants[$constantName]->addReason($error); if ($reflection instanceof Invalid\ReflectionConstant) { foreach ($reflection->getReasons() as $reason) { $this->constants[$constantName]->addReason($reason); } } } else { $this->constants[$constantName] = $reflection; } } if (!empty($errors)) { throw new Exception\FileProcessingException($errors, null); } return $this; } /** * Returns the appropriate source code part. * * Impossible for namespaces. * * @throws \TokenReflection\Exception\RuntimeException If the method is called, because it's unsupported. */ public function getSource() { throw new Exception\RuntimeException('Cannot export source code of a namespace.', Exception\RuntimeException::UNSUPPORTED, $this); } /** * Returns the reflection broker used by this reflection object. * * @return \TokenReflection\Broker|null */ public function getBroker() { return $this->broker; } /** * Magic __get method. * * @param string $key Variable name * @return mixed */ final public function __get($key) { return ReflectionElement::get($this, $key); } /** * Magic __isset method. * * @param string $key Variable name * @return boolean */ final public function __isset($key) { return ReflectionElement::exists($this, $key); } }PHP-Token-Reflection-1.4.0/TokenReflection/ReflectionParameter.php000066400000000000000000000417541237045466400250760ustar00rootroot00000000000000declaringClassName ? null : $this->getBroker()->getClass($this->declaringClassName); } /** * Returns the declaring class name. * * @return string|null */ public function getDeclaringClassName() { return $this->declaringClassName; } /** * Returns the declaring function. * * @return \TokenReflection\ReflectionFunctionBase */ public function getDeclaringFunction() { if (null !== $this->declaringClassName) { // Method parameter $class = $this->getBroker()->getClass($this->declaringClassName); if (null !== $class) { return $class->getMethod($this->declaringFunctionName); } } else { // Function parameter return $this->getBroker()->getFunction($this->declaringFunctionName); } } /** * Returns the declaring function name. * * @return string */ public function getDeclaringFunctionName() { return $this->declaringFunctionName; } /** * Returns the default value. * * @return mixed * @throws \TokenReflection\Exception\RuntimeException If the property is not optional. * @throws \TokenReflection\Exception\RuntimeException If the property has no default value. */ public function getDefaultValue() { if (!$this->isOptional()) { throw new Exception\RuntimeException('Property is not optional.', Exception\RuntimeException::UNSUPPORTED, $this); } if (null === $this->defaultValue) { if (0 === count($this->defaultValueDefinition)) { throw new Exception\RuntimeException('Property has no default value.', Exception\RuntimeException::DOES_NOT_EXIST, $this); } $this->defaultValue = Resolver::getValueDefinition($this->defaultValueDefinition, $this); } return $this->defaultValue; } /** * Returns the part of the source code defining the parameter default value. * * @return string */ public function getDefaultValueDefinition() { return Resolver::getSourceCode($this->defaultValueDefinition); } /** * Returns if the default value is defined by a constant. * * @return boolean */ public function isDefaultValueConstant() { if (!$this->isDefaultValueAvailable() || empty($this->defaultValueDefinition)) { return false; } static $expected = array(T_STRING => true, T_NS_SEPARATOR => true, T_DOUBLE_COLON => true); foreach ($this->defaultValueDefinition as $token) { if (!isset($expected[$token[0]])) { return false; } } return true; } /** * Returns the name of the default value constant. * * @return string|null */ public function getDefaultValueConstantName() { if (!$this->isOptional()) { throw new Exception\RuntimeException('Property is not optional.', Exception\RuntimeException::UNSUPPORTED, $this); } return $this->isDefaultValueConstant() ? $this->getDefaultValueDefinition() : null; } /** * Retutns if a default value for the parameter is available. * * @return boolean */ public function isDefaultValueAvailable() { return $this->isOptional(); } /** * Returns the position within all parameters. * * @return integer */ public function getPosition() { return $this->position; } /** * Returns if the parameter expects an array. * * @return boolean */ public function isArray() { return $this->typeHint === self::ARRAY_TYPE_HINT; } /** * Returns if the parameter expects a callback. * * @return boolean */ public function isCallable() { return $this->typeHint === self::CALLABLE_TYPE_HINT; } /** * Returns the original type hint as defined in the source code. * * @return string|null */ public function getOriginalTypeHint() { return !$this->isArray() && !$this->isCallable() ? ltrim($this->originalTypeHint, '\\') : null; } /** * Returns reflection of the required class of the value. * * @return \TokenReflection\IReflectionClass|null */ public function getClass() { $name = $this->getClassName(); if (null === $name) { return null; } return $this->getBroker()->getClass($name); } /** * Returns the required class name of the value. * * @return string|null * @throws \TokenReflection\Exception\RuntimeException If the type hint class FQN could not be determined. */ public function getClassName() { if ($this->isArray() || $this->isCallable()) { return null; } if (null === $this->typeHint && null !== $this->originalTypeHint) { if (null !== $this->declaringClassName) { $parent = $this->getDeclaringClass(); if (null === $parent) { throw new Exception\RuntimeException('Could not load class reflection.', Exception\RuntimeException::DOES_NOT_EXIST, $this); } } else { $parent = $this->getDeclaringFunction(); if (null === $parent || !$parent->isTokenized()) { throw new Exception\RuntimeException('Could not load function reflection.', Exception\RuntimeException::DOES_NOT_EXIST, $this); } } $lTypeHint = strtolower($this->originalTypeHint); if ('parent' === $lTypeHint || 'self' === $lTypeHint) { if (null === $this->declaringClassName) { throw new Exception\RuntimeException('Parameter type hint cannot be "self" nor "parent" when not a method.', Exception\RuntimeException::UNSUPPORTED, $this); } if ('parent' === $lTypeHint) { if ($parent->isInterface() || null === $parent->getParentClassName()) { throw new Exception\RuntimeException('Class has no parent.', Exception\RuntimeException::DOES_NOT_EXIST, $this); } $this->typeHint = $parent->getParentClassName(); } else { $this->typeHint = $this->declaringClassName; } } else { $this->typeHint = ltrim(Resolver::resolveClassFQN($this->originalTypeHint, $parent->getNamespaceAliases(), $parent->getNamespaceName()), '\\'); } } return $this->typeHint; } /** * Returns if the the parameter allows NULL. * * @return boolean */ public function allowsNull() { if ($this->isArray() || $this->isCallable()) { return 'null' === strtolower($this->getDefaultValueDefinition()); } return null === $this->originalTypeHint || !empty($this->defaultValueDefinition); } /** * Returns if the parameter is optional. * * @return boolean * @throws \TokenReflection\Exception\RuntimeException If it is not possible to determine if the parameter is optional. */ public function isOptional() { if (null === $this->isOptional) { $this->isOptional = !empty($this->defaultValueDefinition) && $this->haveSiblingsDefalutValues(); } return $this->isOptional; } /** * Returns if all following parameters have a default value definition. * * @return boolean */ protected function haveSiblingsDefalutValues() { $function = $this->getDeclaringFunction(); if (null === $function) { throw new Exception\RuntimeException('Could not get the declaring function reflection.', Exception\RuntimeException::DOES_NOT_EXIST, $this); } foreach (array_slice($function->getParameters(), $this->position + 1) as $reflectionParameter) { if (null === $reflectionParameter->getDefaultValueDefinition()) { return false; } } return true; } /** * Returns if the parameter value is passed by reference. * * @return boolean */ public function isPassedByReference() { return $this->passedByReference; } /** * Returns if the paramter value can be passed by value. * * @return boolean */ public function canBePassedByValue() { return !$this->isPassedByReference(); } /** * Returns an element pretty (docblock compatible) name. * * @return string */ public function getPrettyName() { return str_replace('()', '($' . $this->name . ')', $this->getDeclaringFunction()->getPrettyName()); } /** * Returns the string representation of the reflection object. * * @return string */ public function __toString() { if ($this->getClass()) { $hint = $this->getClassName(); } elseif ($this->isArray()) { $hint = self::ARRAY_TYPE_HINT; } elseif ($this->isCallable()) { $hint = self::CALLABLE_TYPE_HINT; } else { $hint = ''; } if (!empty($hint) && $this->allowsNull()) { $hint .= ' or NULL'; } if ($this->isDefaultValueAvailable()) { $default = ' = '; if (null === $this->getDefaultValue()) { $default .= 'NULL'; } elseif (is_array($this->getDefaultValue())) { $default .= 'Array'; } elseif (is_bool($this->getDefaultValue())) { $default .= $this->getDefaultValue() ? 'true' : 'false'; } elseif (is_string($this->getDefaultValue())) { $default .= sprintf("'%s'", str_replace("'", "\\'", $this->getDefaultValue())); } else { $default .= $this->getDefaultValue(); } } else { $default = ''; } return sprintf( 'Parameter #%d [ <%s> %s%s$%s%s ]', $this->getPosition(), $this->isOptional() ? 'optional' : 'required', $hint ? $hint . ' ' : '', $this->isPassedByReference() ? '&' : '', $this->getName(), $default ); } /** * Exports a reflected object. * * @param \TokenReflection\Broker $broker Broker instance * @param string $function Function name * @param string $parameter Parameter name * @param boolean $return Return the export instead of outputting it * @return string|null * @throws \TokenReflection\Exception\RuntimeException If requested parameter doesn't exist. */ public static function export(Broker $broker, $function, $parameter, $return = false) { $functionName = $function; $parameterName = $parameter; $function = $broker->getFunction($functionName); if (null === $function) { throw new Exception\RuntimeException(sprintf('Function %s() does not exist.', $functionName), Exception\RuntimeException::DOES_NOT_EXIST); } $parameter = $function->getParameter($parameterName); if ($return) { return $parameter->__toString(); } echo $parameter->__toString(); } /** * Returns imported namespaces and aliases from the declaring namespace. * * @return array */ public function getNamespaceAliases() { return $this->getDeclaringFunction()->getNamespaceAliases(); } /** * Creates a parameter alias for the given method. * * @param \TokenReflection\ReflectionMethod $parent New parent method * @return \TokenReflection\ReflectionParameter */ public function alias(ReflectionMethod $parent) { $parameter = clone $this; $parameter->declaringClassName = $parent->getDeclaringClassName(); $parameter->declaringFunctionName = $parent->getName(); return $parameter; } /** * Processes the parent reflection object. * * @param \TokenReflection\IReflection $parent Parent reflection object * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionElement * @throws \TokenReflection\Exception\ParseException If an invalid parent reflection object was provided. */ protected function processParent(IReflection $parent, Stream $tokenStream) { if (!$parent instanceof ReflectionFunctionBase) { throw new Exception\ParseException($this, $tokenStream, 'The parent object has to be an instance of TokenReflection\ReflectionFunctionBase.', Exception\ParseException::INVALID_PARENT); } // Declaring function name $this->declaringFunctionName = $parent->getName(); // Position $this->position = count($parent->getParameters()); // Declaring class name if ($parent instanceof ReflectionMethod) { $this->declaringClassName = $parent->getDeclaringClassName(); } return parent::processParent($parent, $tokenStream); } /** * Parses reflected element metadata from the token stream. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @param \TokenReflection\IReflection $parent Parent reflection object * @return \TokenReflection\ReflectionParameter */ protected function parse(Stream $tokenStream, IReflection $parent) { return $this ->parseTypeHint($tokenStream) ->parsePassedByReference($tokenStream) ->parseName($tokenStream) ->parseDefaultValue($tokenStream); } /** * Parses the type hint. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionParameter * @throws \TokenReflection\Exception\ParseException If the type hint class name could not be determined. */ private function parseTypeHint(Stream $tokenStream) { $type = $tokenStream->getType(); if (T_ARRAY === $type) { $this->typeHint = self::ARRAY_TYPE_HINT; $this->originalTypeHint = self::ARRAY_TYPE_HINT; $tokenStream->skipWhitespaces(true); } elseif (T_CALLABLE === $type) { $this->typeHint = self::CALLABLE_TYPE_HINT; $this->originalTypeHint = self::CALLABLE_TYPE_HINT; $tokenStream->skipWhitespaces(true); } elseif (T_STRING === $type || T_NS_SEPARATOR === $type) { $className = ''; do { $className .= $tokenStream->getTokenValue(); $tokenStream->skipWhitespaces(true); $type = $tokenStream->getType(); } while (T_STRING === $type || T_NS_SEPARATOR === $type); if ('' === ltrim($className, '\\')) { throw new Exception\ParseException($this, $tokenStream, sprintf('Invalid class name definition: "%s".', $className), Exception\ParseException::LOGICAL_ERROR); } $this->originalTypeHint = $className; } return $this; } /** * Parses if parameter value is passed by reference. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionParameter */ private function parsePassedByReference(Stream $tokenStream) { if ($tokenStream->is('&')) { $this->passedByReference = true; $tokenStream->skipWhitespaces(true); } return $this; } /** * Parses the constant name. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionParameter * @throws \TokenReflection\Exception\ParseException If the parameter name could not be determined. */ protected function parseName(Stream $tokenStream) { if (!$tokenStream->is(T_VARIABLE)) { throw new Exception\ParseException($this, $tokenStream, 'The parameter name could not be determined.', Exception\ParseException::UNEXPECTED_TOKEN); } $this->name = substr($tokenStream->getTokenValue(), 1); $tokenStream->skipWhitespaces(true); return $this; } /** * Parses the parameter default value. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionParameter * @throws \TokenReflection\Exception\ParseException If the default value could not be determined. */ private function parseDefaultValue(Stream $tokenStream) { if ($tokenStream->is('=')) { $tokenStream->skipWhitespaces(true); $level = 0; while (null !== ($type = $tokenStream->getType())) { switch ($type) { case ')': if (0 === $level) { break 2; } case '}': case ']': $level--; break; case '(': case '{': case '[': $level++; break; case ',': if (0 === $level) { break 2; } break; default: break; } $this->defaultValueDefinition[] = $tokenStream->current(); $tokenStream->next(); } if (')' !== $type && ',' !== $type) { throw new Exception\ParseException($this, $tokenStream, 'The property default value is not terminated properly. Expected "," or ")".', Exception\ParseException::UNEXPECTED_TOKEN); } } return $this; } } PHP-Token-Reflection-1.4.0/TokenReflection/ReflectionProperty.php000066400000000000000000000354621237045466400250010ustar00rootroot00000000000000getBroker()->getClass($this->declaringClassName); } /** * Returns the name of the declaring class. * * @return string */ public function getDeclaringClassName() { return $this->declaringClassName; } /** * Returns the property default value. * * @return mixed */ public function getDefaultValue() { if (is_array($this->defaultValueDefinition)) { $this->defaultValue = Resolver::getValueDefinition($this->defaultValueDefinition, $this); $this->defaultValueDefinition = Resolver::getSourceCode($this->defaultValueDefinition); } return $this->defaultValue; } /** * Returns the part of the source code defining the property default value. * * @return string */ public function getDefaultValueDefinition() { return is_array($this->defaultValueDefinition) ? Resolver::getSourceCode($this->defaultValueDefinition) : $this->defaultValueDefinition; } /** * Returns the property value for a particular class instance. * * @param object $object * @return mixed * @throws \TokenReflection\Exception\RuntimeException If it is not possible to return the property value. */ public function getValue($object) { $declaringClass = $this->getDeclaringClass(); if (!$declaringClass->isInstance($object)) { throw new Exception\RuntimeException('The given class is not an instance or subclass of the current class.', Exception\RuntimeException::INVALID_ARGUMENT, $this); } if ($this->isPublic()) { return $object->{$this->name}; } elseif ($this->isAccessible()) { $refClass = new InternalReflectionClass($object); $refProperty = $refClass->getProperty($this->name); $refProperty->setAccessible(true); $value = $refProperty->getValue($object); $refProperty->setAccessible(false); return $value; } throw new Exception\RuntimeException('Only public and accessible properties can return their values.', Exception\RuntimeException::NOT_ACCESSBILE, $this); } /** * Returns if the property was created at compile time. * * All properties in the source code are. * * @return boolean */ public function isDefault() { return true; } /** * Returns property modifiers. * * @return integer */ public function getModifiers() { if (false === $this->modifiersComplete) { $declaringClass = $this->getDeclaringClass(); $declaringClassParent = $declaringClass->getParentClass(); if ($declaringClassParent && $declaringClassParent->hasProperty($this->name)) { $property = $declaringClassParent->getProperty($this->name); if (($this->isPublic() && !$property->isPublic()) || ($this->isProtected() && $property->isPrivate())) { $this->modifiers |= self::ACCESS_LEVEL_CHANGED; } } $this->modifiersComplete = ($this->modifiers & self::ACCESS_LEVEL_CHANGED) || $declaringClass->isComplete(); } return $this->modifiers; } /** * Returns if the property is private. * * @return boolean */ public function isPrivate() { return (bool) ($this->modifiers & InternalReflectionProperty::IS_PRIVATE); } /** * Returns if the property is protected. * * @return boolean */ public function isProtected() { return (bool) ($this->modifiers & InternalReflectionProperty::IS_PROTECTED); } /** * Returns if the property is public. * * @return boolean */ public function isPublic() { return (bool) ($this->modifiers & InternalReflectionProperty::IS_PUBLIC); } /** * Returns if the poperty is static. * * @return boolean */ public function isStatic() { return (bool) ($this->modifiers & InternalReflectionProperty::IS_STATIC); } /** * Returns the string representation of the reflection object. * * @return string */ public function __toString() { return sprintf( "Property [ %s%s%s%s%s\$%s ]\n", $this->isStatic() ? '' : ' ', $this->isPublic() ? 'public ' : '', $this->isPrivate() ? 'private ' : '', $this->isProtected() ? 'protected ' : '', $this->isStatic() ? 'static ' : '', $this->getName() ); } /** * Exports a reflected object. * * @param \TokenReflection\Broker $broker Broker instance * @param string|object $class Class name or class instance * @param string $property Property name * @param boolean $return Return the export instead of outputting it * @return string|null * @throws \TokenReflection\Exception\RuntimeException If requested parameter doesn't exist. */ public static function export(Broker $broker, $class, $property, $return = false) { $className = is_object($class) ? get_class($class) : $class; $propertyName = $property; $class = $broker->getClass($className); if ($class instanceof Invalid\ReflectionClass) { throw new Exception\RuntimeException('Class is invalid.', Exception\RuntimeException::UNSUPPORTED); } elseif ($class instanceof Dummy\ReflectionClass) { throw new Exception\RuntimeException(sprintf('Class %s does not exist.', $className), Exception\RuntimeException::DOES_NOT_EXIST); } $property = $class->getProperty($propertyName); if ($return) { return $property->__toString(); } echo $property->__toString(); } /** * Returns if the property is set accessible. * * @return boolean */ public function isAccessible() { return $this->accessible; } /** * Sets a property to be accessible or not. * * @param boolean $accessible If the property should be accessible. */ public function setAccessible($accessible) { $this->accessible = (bool) $accessible; } /** * Sets the property default value. * * @param mixed $value */ public function setDefaultValue($value) { $this->defaultValue = $value; $this->defaultValueDefinition = var_export($value, true); } /** * Sets value of a property for a particular class instance. * * @param object $object Class instance * @param mixed $value Poperty value * @throws \TokenReflection\Exception\RuntimeException If it is not possible to set the property value. */ public function setValue($object, $value) { $declaringClass = $this->getDeclaringClass(); if (!$declaringClass->isInstance($object)) { throw new Exception\RuntimeException('Instance of or subclass expected.', Exception\RuntimeException::INVALID_ARGUMENT, $this); } if ($this->isPublic()) { $object->{$this->name} = $value; } elseif ($this->isAccessible()) { $refClass = new InternalReflectionClass($object); $refProperty = $refClass->getProperty($this->name); $refProperty->setAccessible(true); $refProperty->setValue($object, $value); $refProperty->setAccessible(false); if ($this->isStatic()) { $this->setDefaultValue($value); } } else { throw new Exception\RuntimeException('Only public and accessible properties can be set.', Exception\RuntimeException::NOT_ACCESSBILE, $this); } } /** * Returns imported namespaces and aliases from the declaring namespace. * * @return array */ public function getNamespaceAliases() { return $this->getDeclaringClass()->getNamespaceAliases(); } /** * Creates a property alias for the given class. * * @param \TokenReflection\ReflectionClass $parent New parent class * @return \TokenReflection\ReflectionProperty */ public function alias(ReflectionClass $parent) { $property = clone $this; $property->declaringClassName = $parent->getName(); return $property; } /** * Returns the defining trait. * * @return \TokenReflection\IReflectionClass|null */ public function getDeclaringTrait() { return null === $this->declaringTraitName ? null : $this->getBroker()->getClass($this->declaringTraitName); } /** * Returns the declaring trait name. * * @return string|null */ public function getDeclaringTraitName() { return $this->declaringTraitName; } /** * Returns an element pretty (docblock compatible) name. * * @return string */ public function getPrettyName() { return sprintf('%s::$%s', $this->declaringClassName ?: $this->declaringTraitName, $this->name); } /** * Processes the parent reflection object. * * @param \TokenReflection\IReflection $parent Parent reflection object * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionElement * @throws \TokenReflection\Exception\Parse If an invalid parent reflection object was provided. */ protected function processParent(IReflection $parent, Stream $tokenStream) { if (!$parent instanceof ReflectionClass) { throw new Exception\ParseException($this, $tokenStream, 'The parent object has to be an instance of TokenReflection\ReflectionClass.', Exception\ParseException::INVALID_PARENT); } $this->declaringClassName = $parent->getName(); if ($parent->isTrait()) { $this->declaringTraitName = $parent->getName(); } return parent::processParent($parent, $tokenStream); } /** * Parses reflected element metadata from the token stream. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @param \TokenReflection\IReflection $parent Parent reflection object * @return \TokenReflection\ReflectionProperty */ protected function parse(Stream $tokenStream, IReflection $parent) { $this->parseModifiers($tokenStream, $parent); if (false === $this->docComment->getDocComment()) { $this->parseDocComment($tokenStream, $parent); } return $this->parseName($tokenStream) ->parseDefaultValue($tokenStream); } /** * Parses class modifiers (abstract, final) and class type (class, interface). * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @param \TokenReflection\ReflectionClass $class Defining class * @return \TokenReflection\ReflectionClass * @throws \TokenReflection\Exception\ParseException If the modifiers value cannot be determined. */ private function parseModifiers(Stream $tokenStream, ReflectionClass $class) { while (true) { switch ($tokenStream->getType()) { case T_PUBLIC: case T_VAR: $this->modifiers |= InternalReflectionProperty::IS_PUBLIC; break; case T_PROTECTED: $this->modifiers |= InternalReflectionProperty::IS_PROTECTED; break; case T_PRIVATE: $this->modifiers |= InternalReflectionProperty::IS_PRIVATE; break; case T_STATIC: $this->modifiers |= InternalReflectionProperty::IS_STATIC; break; default: break 2; } $tokenStream->skipWhitespaces(true); } if (InternalReflectionProperty::IS_STATIC === $this->modifiers) { $this->modifiers |= InternalReflectionProperty::IS_PUBLIC; } elseif (0 === $this->modifiers) { $parentProperties = $class->getOwnProperties(); if (empty($parentProperties)) { throw new Exception\ParseException($this, $tokenStream, 'No access level defined and no previous defining class property present.', Exception\ParseException::LOGICAL_ERROR); } $sibling = array_pop($parentProperties); if ($sibling->isPublic()) { $this->modifiers = InternalReflectionProperty::IS_PUBLIC; } elseif ($sibling->isPrivate()) { $this->modifiers = InternalReflectionProperty::IS_PRIVATE; } elseif ($sibling->isProtected()) { $this->modifiers = InternalReflectionProperty::IS_PROTECTED; } else { throw new Exception\ParseException($this, $tokenStream, sprintf('Property sibling "%s" has no access level defined.', $sibling->getName()), Exception\Parse::PARSE_ELEMENT_ERROR); } if ($sibling->isStatic()) { $this->modifiers |= InternalReflectionProperty::IS_STATIC; } } return $this; } /** * Parses the property name. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionProperty * @throws \TokenReflection\Exception\ParseException If the property name could not be determined. */ protected function parseName(Stream $tokenStream) { if (!$tokenStream->is(T_VARIABLE)) { throw new Exception\ParseException($this, $tokenStream, 'The property name could not be determined.', Exception\ParseException::LOGICAL_ERROR); } $this->name = substr($tokenStream->getTokenValue(), 1); $tokenStream->skipWhitespaces(true); return $this; } /** * Parses the propety default value. * * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream * @return \TokenReflection\ReflectionProperty * @throws \TokenReflection\Exception\ParseException If the property default value could not be determined. */ private function parseDefaultValue(Stream $tokenStream) { $type = $tokenStream->getType(); if (';' === $type || ',' === $type) { // No default value return $this; } if ('=' === $type) { $tokenStream->skipWhitespaces(true); } $level = 0; while (null !== ($type = $tokenStream->getType())) { switch ($type) { case ',': if (0 !== $level) { break; } case ';': break 2; case ')': case ']': case '}': $level--; break; case '(': case '{': case '[': $level++; break; default: break; } $this->defaultValueDefinition[] = $tokenStream->current(); $tokenStream->next(); } if (',' !== $type && ';' !== $type) { throw new Exception\ParseException($this, $tokenStream, 'The property default value is not terminated properly. Expected "," or ";".', Exception\ParseException::UNEXPECTED_TOKEN); } return $this; } } PHP-Token-Reflection-1.4.0/TokenReflection/Resolver.php000066400000000000000000000220041237045466400227270ustar00rootroot00000000000000getNamespaceName(); } elseif ($reflection instanceof ReflectionParameter) { $namespace = $reflection->getDeclaringFunction()->getNamespaceName(); } elseif ($reflection instanceof ReflectionProperty || $reflection instanceof ReflectionMethod) { $namespace = $reflection->getDeclaringClass()->getNamespaceName(); } else { throw new Exception\RuntimeException('Invalid reflection object given.', Exception\RuntimeException::INVALID_ARGUMENT, $reflection); } // Process __LINE__ constants; replace with the line number of the corresponding token foreach ($tokens as $index => $token) { if (T_LINE === $token[0]) { $tokens[$index] = array( T_LNUMBER, $token[2], $token[2] ); } } $source = self::getSourceCode($tokens); $constants = self::findConstants($tokens, $reflection); if (!empty($constants)) { foreach (array_reverse($constants, true) as $offset => $constant) { $value = ''; try { switch ($constant) { case '__FILE__': $value = $reflection->getFileName(); break; case '__DIR__': $value = dirname($reflection->getFileName()); break; case '__FUNCTION__': if ($reflection instanceof IReflectionParameter) { $value = $reflection->getDeclaringFunctionName(); } elseif ($reflection instanceof IReflectionFunctionBase) { $value = $reflection->getName(); } break; case '__CLASS__': if ($reflection instanceof IReflectionConstant || $reflection instanceof IReflectionParameter || $reflection instanceof IReflectionProperty || $reflection instanceof IReflectionMethod) { $value = $reflection->getDeclaringClassName() ?: ''; } break; case '__TRAIT__': if ($reflection instanceof IReflectionMethod || $reflection instanceof IReflectionProperty) { $value = $reflection->getDeclaringTraitName() ?: ''; } elseif ($reflection instanceof IReflectionParameter) { $method = $reflection->getDeclaringFunction(); if ($method instanceof IReflectionMethod) { $value = $method->getDeclaringTraitName() ?: ''; } } break; case '__METHOD__': if ($reflection instanceof IReflectionParameter) { if (null !== $reflection->getDeclaringClassName()) { $value = $reflection->getDeclaringClassName() . '::' . $reflection->getDeclaringFunctionName(); } else { $value = $reflection->getDeclaringFunctionName(); } } elseif ($reflection instanceof IReflectionConstant || $reflection instanceof IReflectionProperty) { $value = $reflection->getDeclaringClassName() ?: ''; } elseif ($reflection instanceof IReflectionMethod) { $value = $reflection->getDeclaringClassName() . '::' . $reflection->getName(); } elseif ($reflection instanceof IReflectionFunction) { $value = $reflection->getName(); } break; case '__NAMESPACE__': if (($reflection instanceof IReflectionConstant && null !== $reflection->getDeclaringClassName()) || $reflection instanceof IReflectionProperty) { $value = $reflection->getDeclaringClass()->getNamespaceName(); } elseif ($reflection instanceof IReflectionParameter) { if (null !== $reflection->getDeclaringClassName()) { $value = $reflection->getDeclaringClass()->getNamespaceName(); } else { $value = $reflection->getDeclaringFunction()->getNamespaceName(); } } elseif ($reflection instanceof IReflectionMethod) { $value = $reflection->getDeclaringClass()->getNamespaceName(); } else { $value = $reflection->getNamespaceName(); } break; default: if (0 === stripos($constant, 'self::') || 0 === stripos($constant, 'parent::')) { // Handle self:: and parent:: definitions if ($reflection instanceof ReflectionConstant && null === $reflection->getDeclaringClassName()) { throw new Exception\RuntimeException('Top level constants cannot use self:: and parent:: references.', Exception\RuntimeException::UNSUPPORTED, $reflection); } elseif ($reflection instanceof ReflectionParameter && null === $reflection->getDeclaringClassName()) { throw new Exception\RuntimeException('Function parameters cannot use self:: and parent:: references.', Exception\RuntimeException::UNSUPPORTED, $reflection); } if (0 === stripos($constant, 'self::')) { $className = $reflection->getDeclaringClassName(); } else { $declaringClass = $reflection->getDeclaringClass(); $className = $declaringClass->getParentClassName() ?: self::CONSTANT_NOT_FOUND; } $constantName = $className . substr($constant, strpos($constant, '::')); } else { $constantName = self::resolveClassFQN($constant, $reflection->getNamespaceAliases(), $namespace); if ($cnt = strspn($constant, '\\')) { $constantName = str_repeat('\\', $cnt) . $constantName; } } $constantReflection = $reflection->getBroker()->getConstant($constantName); $value = $constantReflection->getValue(); } } catch (Exception\RuntimeException $e) { $value = self::CONSTANT_NOT_FOUND; } $source = substr_replace($source, var_export($value, true), $offset, strlen($constant)); } } return self::evaluate(sprintf("return %s;\n", $source)); } /** * Returns a part of the source code defined by given tokens. * * @param array $tokens Tokens array * @return array */ final public static function getSourceCode(array $tokens) { if (empty($tokens)) { return null; } $source = ''; foreach ($tokens as $token) { $source .= $token[1]; } return $source; } /** * Finds constant names in the token definition. * * @param array $tokens Tokenized source code * @param \TokenReflection\ReflectionElement $reflection Caller reflection * @return array */ final public static function findConstants(array $tokens, ReflectionElement $reflection) { static $accepted = array( T_DOUBLE_COLON => true, T_STRING => true, T_NS_SEPARATOR => true, T_CLASS_C => true, T_DIR => true, T_FILE => true, T_LINE => true, T_FUNC_C => true, T_METHOD_C => true, T_NS_C => true, T_TRAIT_C => true ); static $dontResolve = array('true' => true, 'false' => true, 'null' => true); // Adding a dummy token to the end $tokens[] = array(null); $constants = array(); $constant = ''; $offset = 0; foreach ($tokens as $token) { if (isset($accepted[$token[0]])) { $constant .= $token[1]; } elseif ('' !== $constant) { if (!isset($dontResolve[strtolower($constant)])) { $constants[$offset - strlen($constant)] = $constant; } $constant = ''; } if (null !== $token[0]) { $offset += strlen($token[1]); } } return $constants; } /** * Evaluates a source code. * * @param string $source Source code * @return mixed */ final private static function evaluate($source) { return eval($source); } } PHP-Token-Reflection-1.4.0/TokenReflection/Stream/000077500000000000000000000000001237045466400216525ustar00rootroot00000000000000PHP-Token-Reflection-1.4.0/TokenReflection/Stream/FileStream.php000066400000000000000000000022261237045466400244200ustar00rootroot00000000000000fileName = Broker::getRealPath($fileName); if (false === $this->fileName) { throw new Exception\StreamException($this, 'File does not exist.', Exception\StreamException::DOES_NOT_EXIST); } $contents = @file_get_contents($this->fileName); if (false === $contents) { throw new Exception\StreamException($this, 'File is not readable.', Exception\StreamException::NOT_READABLE); } $this->processSource($contents); } }PHP-Token-Reflection-1.4.0/TokenReflection/Stream/StreamBase.php000066400000000000000000000261321237045466400244150ustar00rootroot00000000000000 true, T_WHITESPACE => true, T_DOC_COMMENT => true, T_INLINE_HTML => true, T_ENCAPSED_AND_WHITESPACE => true, T_CONSTANT_ENCAPSED_STRING => true); foreach ($stream as $position => $token) { if (is_array($token)) { if (!NATIVE_TRAITS && T_STRING === $token[0]) { $lValue = strtolower($token[1]); if ('trait' === $lValue) { $token[0] = T_TRAIT; } elseif ('insteadof' === $lValue) { $token[0] = T_INSTEADOF; } elseif ('__TRAIT__' === $token[1]) { $token[0] = T_TRAIT_C; } elseif ('callable' === $lValue) { $token[0] = T_CALLABLE; } } $this->tokens[] = $token; } else { $previous = $this->tokens[$position - 1]; $line = $previous[2]; if (isset($checkLines[$previous[0]])) { $line += substr_count($previous[1], "\n"); } $this->tokens[] = array($token, $token, $line); } } $this->count = count($this->tokens); } /** * Returns the file name this is a part of. * * @return string */ public function getFileName() { return $this->fileName; } /** * Returns the original source code. * * @return string */ public function getSource() { return $this->getSourcePart(); } /** * Returns a part of the source code. * * @param mixed $start Start offset * @param mixed $end End offset * @return string */ public function getSourcePart($start = null, $end = null) { $start = (int) $start; $end = null === $end ? ($this->count - 1) : (int) $end; $source = ''; for ($i = $start; $i <= $end; $i++) { $source .= $this->tokens[$i][1]; } return $source; } /** * Finds the position of the token of the given type. * * @param integer|string $type Token type * @return \TokenReflection\Stream|boolean */ public function find($type) { $actual = $this->position; while (isset($this->tokens[$this->position])) { if ($type === $this->tokens[$this->position][0]) { return $this; } $this->position++; } $this->position = $actual; return false; } /** * Returns the position of the token with the matching bracket. * * @return \TokenReflection\Stream * @throws \TokenReflection\Exception\RuntimeException If out of the token stream. * @throws \TokenReflection\Exception\RuntimeException If there is no bracket at the current position. * @throws \TokenReflection\Exception\RuntimeException If the matching bracket could not be found. */ public function findMatchingBracket() { static $brackets = array( '(' => ')', '{' => '}', '[' => ']', T_CURLY_OPEN => '}', T_DOLLAR_OPEN_CURLY_BRACES => '}' ); if (!$this->valid()) { throw new Exception\StreamException($this, 'Out of token stream.', Exception\StreamException::READ_BEYOND_EOS); } $position = $this->position; $bracket = $this->tokens[$this->position][0]; if (!isset($brackets[$bracket])) { throw new Exception\StreamException($this, sprintf('There is no usable bracket at position "%d".', $position), Exception\StreamException::DOES_NOT_EXIST); } $searching = $brackets[$bracket]; $level = 0; while (isset($this->tokens[$this->position])) { $type = $this->tokens[$this->position][0]; if ($searching === $type) { $level--; } elseif ($bracket === $type || ($searching === '}' && ('{' === $type || T_CURLY_OPEN === $type || T_DOLLAR_OPEN_CURLY_BRACES === $type))) { $level++; } if (0 === $level) { return $this; } $this->position++; } throw new Exception\StreamException($this, sprintf('Could not find the end bracket "%s" of the bracket at position "%d".', $searching, $position), Exception\StreamException::DOES_NOT_EXIST); } /** * Skips whitespaces and comments next to the current position. * * @param boolean $skipDocBlocks Skip docblocks as well * @return \TokenReflection\Stream\StreamBase */ public function skipWhitespaces($skipDocBlocks = false) { static $skipped = array(T_WHITESPACE => true, T_COMMENT => true, T_DOC_COMMENT => true); do { $this->position++; } while (isset($this->tokens[$this->position]) && isset($skipped[$this->tokens[$this->position][0]]) && ($skipDocBlocks || $this->tokens[$this->position][0] !== T_DOC_COMMENT)); return $this; } /** * Returns if the token stream is at a whitespace position. * * @param boolean $docBlock Consider docblocks as whitespaces * @return boolean */ public function isWhitespace($docBlock = false) { static $skipped = array(T_WHITESPACE => true, T_COMMENT => true, T_DOC_COMMENT => false); if (!$this->valid()) { return false; } return $docBlock ? isset($skipped[$this->getType()]) : !empty($skipped[$this->getType()]); } /** * Checks if there is a token of the given type at the given position. * * @param integer|string $type Token type * @param integer $position Position; if none given, consider the current iteration position * @return boolean */ public function is($type, $position = -1) { return $type === $this->getType($position); } /** * Returns the type of a token. * * @param integer $position Token position; if none given, consider the current iteration position * @return string|integer|null */ public function getType($position = -1) { if (-1 === $position) { $position = $this->position; } return isset($this->tokens[$position]) ? $this->tokens[$position][0] : null; } /** * Returns the current token value. * * @param integer $position Token position; if none given, consider the current iteration position * @return stirng */ public function getTokenValue($position = -1) { if (-1 === $position) { $position = $this->position; } return isset($this->tokens[$position]) ? $this->tokens[$position][1] : null; } /** * Returns the token type name. * * @param integer $position Token position; if none given, consider the current iteration position * @return string|null */ public function getTokenName($position = -1) { $type = $this->getType($position); if (is_string($type)) { return $type; } elseif (T_TRAIT === $type) { return 'T_TRAIT'; } elseif (T_INSTEADOF === $type) { return 'T_INSTEADOF'; } elseif (T_CALLABLE === $type) { return 'T_CALLABLE'; } return token_name($type); } /** * Stream serialization. * * @return string */ public function serialize() { return serialize(array($this->fileName, $this->tokens)); } /** * Restores the stream from the serialized state. * * @param string $serialized Serialized form * @throws \TokenReflection\Exception\StreamException On deserialization error. */ public function unserialize($serialized) { $data = @unserialize($serialized); if (false === $data) { throw new Exception\StreamException($this, 'Could not deserialize the serialized data.', Exception\StreamException::SERIALIZATION_ERROR); } if (2 !== count($data) || !is_string($data[0]) || !is_array($data[1])) { throw new Exception\StreamException($this, 'Invalid serialization data.', Exception\StreamException::SERIALIZATION_ERROR); } $this->fileName = $data[0]; $this->tokens = $data[1]; $this->count = count($this->tokens); $this->position = 0; } /** * Checks of there is a token with the given index. * * @param integer $offset Token index * @return boolean */ public function offsetExists($offset) { return isset($this->tokens[$offset]); } /** * Removes a token. * * Unsupported. * * @param integer $offset Position * @throws \TokenReflection\Exception\StreamException Unsupported. */ public function offsetUnset($offset) { throw new Exception\StreamException($this, 'Removing of tokens from the stream is not supported.', Exception\StreamException::UNSUPPORTED); } /** * Returns a token at the given index. * * @param integer $offset Token index * @return mixed */ public function offsetGet($offset) { return isset($this->tokens[$offset]) ? $this->tokens[$offset] : null; } /** * Sets a value of a particular token. * * Unsupported * * @param integer $offset Position * @param mixed $value Value * @throws \TokenReflection\Exception\StreamException Unsupported. */ public function offsetSet($offset, $value) { throw new Exception\StreamException($this, 'Setting token values is not supported.', Exception\StreamException::UNSUPPORTED); } /** * Returns the current internal pointer value. * * @return integer */ public function key() { return $this->position; } /** * Advances the internal pointer. * * @return \TokenReflection\Stream */ public function next() { $this->position++; return $this; } /** * Sets the internal pointer to zero. * * @return \TokenReflection\Stream */ public function rewind() { $this->position = 0; return $this; } /** * Returns the current token. * * @return array|null */ public function current() { return isset($this->tokens[$this->position]) ? $this->tokens[$this->position] : null; } /** * Checks if there is a token on the current position. * * @return boolean */ public function valid() { return isset($this->tokens[$this->position]); } /** * Returns the number of tokens in the stream. * * @return integer */ public function count() { return $this->count; } /** * Sets the internal pointer to the given value. * * @param integer $position New position * @return \TokenReflection\Stream */ public function seek($position) { $this->position = (int) $position; return $this; } /** * Returns the stream source code. * * @return string */ public function __toString() { return $this->getSource(); } } PHP-Token-Reflection-1.4.0/TokenReflection/Stream/StringStream.php000066400000000000000000000012571237045466400250120ustar00rootroot00000000000000fileName = $fileName; $this->processSource($source); } }PHP-Token-Reflection-1.4.0/composer.json000066400000000000000000000011711237045466400200460ustar00rootroot00000000000000{ "name": "andrewsville/php-token-reflection", "type": "library", "description": "Library emulating the PHP internal reflection using just the tokenized source code.", "keywords": ["library", "tokenizer", "reflection"], "homepage": "http://andrewsville.github.com/PHP-Token-Reflection/", "license": "BSD-3", "authors": [ { "name": "Ondřej Nešpor", "homepage": "https://github.com/Andrewsville" }, { "name": "Jaroslav Hanslík", "homepage": "https://github.com/kukulich" } ], "require": { "php": ">=5.3.0", "ext-tokenizer": "*" }, "autoload": { "psr-0": { "TokenReflection": "./" } } }