PDF rausgenommen

This commit is contained in:
aschwarz
2023-01-23 11:03:31 +01:00
parent 82d562a322
commit a6523903eb
28078 changed files with 4247552 additions and 2 deletions

View File

@@ -0,0 +1,32 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Annotation;
use ArrayObject;
class AnnotationCollection extends ArrayObject
{
/**
* Checks if the collection has annotations for a class
*
* @param string $class
* @return bool
*/
public function hasAnnotation($class)
{
foreach ($this as $annotation) {
if (get_class($annotation) == $class) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,21 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Annotation;
interface AnnotationInterface
{
/**
* Initialize
*
* @param string $content
* @return void
*/
public function initialize($content);
}

View File

@@ -0,0 +1,109 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Annotation;
use Zend\Code\Annotation\Parser\ParserInterface;
use Zend\EventManager\Event;
use Zend\EventManager\EventManager;
use Zend\EventManager\EventManagerAwareInterface;
use Zend\EventManager\EventManagerInterface;
/**
* Pluggable annotation manager
*
* Simply composes an EventManager. When createAnnotation() is called, it fires
* off an event of the same name, passing it the resolved annotation class, the
* annotation content, and the raw annotation string; the first listener to
* return an object will halt execution of the event, and that object will be
* returned as the annotation.
*/
class AnnotationManager implements EventManagerAwareInterface
{
const EVENT_CREATE_ANNOTATION = 'createAnnotation';
/**
* @var EventManagerInterface
*/
protected $events;
/**
* Set the event manager instance
*
* @param EventManagerInterface $events
* @return AnnotationManager
*/
public function setEventManager(EventManagerInterface $events)
{
$events->setIdentifiers(array(
__CLASS__,
get_class($this),
));
$this->events = $events;
return $this;
}
/**
* Retrieve event manager
*
* Lazy loads an instance if none registered.
*
* @return EventManagerInterface
*/
public function getEventManager()
{
if (null === $this->events) {
$this->setEventManager(new EventManager());
}
return $this->events;
}
/**
* Attach a parser to listen to the createAnnotation event
*
* @param ParserInterface $parser
* @return AnnotationManager
*/
public function attach(ParserInterface $parser)
{
$this->getEventManager()
->attach(self::EVENT_CREATE_ANNOTATION, array($parser, 'onCreateAnnotation'));
return $this;
}
/**
* Create Annotation
*
* @param string[] $annotationData
* @return false|\stdClass
*/
public function createAnnotation(array $annotationData)
{
$event = new Event();
$event->setName(self::EVENT_CREATE_ANNOTATION);
$event->setTarget($this);
$event->setParams(array(
'class' => $annotationData[0],
'content' => $annotationData[1],
'raw' => $annotationData[2],
));
$eventManager = $this->getEventManager();
$results = $eventManager->trigger($event, function ($r) {
return (is_object($r));
});
$annotation = $results->last();
return (is_object($annotation) ? $annotation : false);
}
}

View File

@@ -0,0 +1,153 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Annotation\Parser;
use Doctrine\Common\Annotations\AnnotationRegistry;
use Doctrine\Common\Annotations\DocParser;
use Traversable;
use Zend\Code\Exception;
use Zend\EventManager\EventInterface;
/**
* A parser for docblock annotations that utilizes the annotation parser from
* Doctrine\Common.
*
* Consumes Doctrine\Common\Annotations\DocParser, and responds to events from
* AnnotationManager. If the annotation examined is in the list of classes we
* are interested in, the raw annotation is passed to the DocParser in order to
* retrieve the annotation object instance. Otherwise, it is skipped.
*/
class DoctrineAnnotationParser implements ParserInterface
{
/**
* @var array Annotation classes we support on this iteration
*/
protected $allowedAnnotations = array();
/**
* @var DocParser
*/
protected $docParser;
public function __construct()
{
// Hack to ensure an attempt to autoload an annotation class is made
AnnotationRegistry::registerLoader(function ($class) {
return (bool) class_exists($class);
});
}
/**
* Set the DocParser instance
*
* @param DocParser $docParser
* @return DoctrineAnnotationParser
*/
public function setDocParser(DocParser $docParser)
{
$this->docParser = $docParser;
return $this;
}
/**
* Retrieve the DocParser instance
*
* If none is registered, lazy-loads a new instance.
*
* @return DocParser
*/
public function getDocParser()
{
if (!$this->docParser instanceof DocParser) {
$this->setDocParser(new DocParser());
}
return $this->docParser;
}
/**
* Handle annotation creation
*
* @param EventInterface $e
* @return false|\stdClass
*/
public function onCreateAnnotation(EventInterface $e)
{
$annotationClass = $e->getParam('class', false);
if (!$annotationClass) {
return false;
}
if (!isset($this->allowedAnnotations[$annotationClass])) {
return false;
}
$annotationString = $e->getParam('raw', false);
if (!$annotationString) {
return false;
}
// Annotation classes provided by the AnnotationScanner are already
// resolved to fully-qualified class names. Adding the global namespace
// prefix allows the Doctrine annotation parser to locate the annotation
// class correctly.
$annotationString = preg_replace('/^(@)/', '$1\\', $annotationString);
$parser = $this->getDocParser();
$annotations = $parser->parse($annotationString);
if (empty($annotations)) {
return false;
}
$annotation = array_shift($annotations);
if (!is_object($annotation)) {
return false;
}
return $annotation;
}
/**
* Specify an allowed annotation class
*
* @param string $annotation
* @return DoctrineAnnotationParser
*/
public function registerAnnotation($annotation)
{
$this->allowedAnnotations[$annotation] = true;
return $this;
}
/**
* Set many allowed annotations at once
*
* @param array|Traversable $annotations Array or traversable object of
* annotation class names
* @throws Exception\InvalidArgumentException
* @return DoctrineAnnotationParser
*/
public function registerAnnotations($annotations)
{
if (!is_array($annotations) && !$annotations instanceof Traversable) {
throw new Exception\InvalidArgumentException(sprintf(
'%s: expects an array or Traversable; received "%s"',
__METHOD__,
(is_object($annotations) ? get_class($annotations) : gettype($annotations))
));
}
foreach ($annotations as $annotation) {
$this->allowedAnnotations[$annotation] = true;
}
return $this;
}
}

View File

@@ -0,0 +1,224 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Annotation\Parser;
use Traversable;
use Zend\Code\Annotation\AnnotationInterface;
use Zend\Code\Exception;
use Zend\EventManager\EventInterface;
/**
* Generic annotation parser
*
* Expects registration of AnnotationInterface instances. Such instances
* will be passed annotation content to their initialize() method, which
* they are then responsible for parsing.
*/
class GenericAnnotationParser implements ParserInterface
{
/**
* @var array
*/
protected $aliases = array();
/**
* @var array
*/
protected $annotationNames = array();
/**
* @var AnnotationInterface[]
*/
protected $annotations = array();
/**
* Listen to onCreateAnnotation, and attempt to return an annotation object
* instance.
*
* If the annotation class or alias is not registered, immediately returns
* false. Otherwise, resolves the class, clones it, and, if any content is
* present, calls {@link AnnotationInterface::initialize()} with the
* content.
*
* @param EventInterface $e
* @return false|AnnotationInterface
*/
public function onCreateAnnotation(EventInterface $e)
{
$class = $e->getParam('class', false);
if (!$class || !$this->hasAnnotation($class)) {
return false;
}
$content = $e->getParam('content', '');
$content = trim($content, '()');
if ($this->hasAlias($class)) {
$class = $this->resolveAlias($class);
}
$index = array_search($class, $this->annotationNames);
$annotation = $this->annotations[$index];
$newAnnotation = clone $annotation;
if ($content) {
$newAnnotation->initialize($content);
}
return $newAnnotation;
}
/**
* Register annotations
*
* @param string|AnnotationInterface $annotation String class name of an
* AnnotationInterface implementation, or actual instance
* @return GenericAnnotationParser
* @throws Exception\InvalidArgumentException
*/
public function registerAnnotation($annotation)
{
$class = false;
if (is_string($annotation) && class_exists($annotation)) {
$class = $annotation;
$annotation = new $annotation();
}
if (!$annotation instanceof AnnotationInterface) {
throw new Exception\InvalidArgumentException(sprintf(
'%s: expects an instance of %s\AnnotationInterface; received "%s"',
__METHOD__,
__NAMESPACE__,
(is_object($annotation) ? get_class($annotation) : gettype($annotation))
));
}
$class = $class ?: get_class($annotation);
if (in_array($class, $this->annotationNames)) {
throw new Exception\InvalidArgumentException(sprintf(
'An annotation for this class %s already exists',
$class
));
}
$this->annotations[] = $annotation;
$this->annotationNames[] = $class;
}
/**
* Register many annotations at once
*
* @param array|Traversable $annotations
* @throws Exception\InvalidArgumentException
* @return GenericAnnotationParser
*/
public function registerAnnotations($annotations)
{
if (!is_array($annotations) && !$annotations instanceof Traversable) {
throw new Exception\InvalidArgumentException(sprintf(
'%s: expects an array or Traversable; received "%s"',
__METHOD__,
(is_object($annotations) ? get_class($annotations) : gettype($annotations))
));
}
foreach ($annotations as $annotation) {
$this->registerAnnotation($annotation);
}
return $this;
}
/**
* Checks if the manager has annotations for a class
*
* @param string $class
* @return bool
*/
public function hasAnnotation($class)
{
if (in_array($class, $this->annotationNames)) {
return true;
}
if ($this->hasAlias($class)) {
return true;
}
return false;
}
/**
* Alias an annotation name
*
* @param string $alias
* @param string $class May be either a registered annotation name or another alias
* @throws Exception\InvalidArgumentException
* @return GenericAnnotationParser
*/
public function setAlias($alias, $class)
{
if (!in_array($class, $this->annotationNames) && !$this->hasAlias($class)) {
throw new Exception\InvalidArgumentException(sprintf(
'%s: Cannot alias "%s" to "%s", as class "%s" is not currently a registered annotation or alias',
__METHOD__,
$alias,
$class,
$class
));
}
$alias = $this->normalizeAlias($alias);
$this->aliases[$alias] = $class;
return $this;
}
/**
* Normalize an alias name
*
* @param string $alias
* @return string
*/
protected function normalizeAlias($alias)
{
return strtolower(str_replace(array('-', '_', ' ', '\\', '/'), '', $alias));
}
/**
* Do we have an alias by the provided name?
*
* @param string $alias
* @return bool
*/
protected function hasAlias($alias)
{
$alias = $this->normalizeAlias($alias);
return (isset($this->aliases[$alias]));
}
/**
* Resolve an alias to a class name
*
* @param string $alias
* @return string
*/
protected function resolveAlias($alias)
{
do {
$normalized = $this->normalizeAlias($alias);
$class = $this->aliases[$normalized];
} while ($this->hasAlias($class));
return $class;
}
}

View File

@@ -0,0 +1,39 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Annotation\Parser;
use Zend\EventManager\EventInterface;
interface ParserInterface
{
/**
* Respond to the "createAnnotation" event
*
* @param EventInterface $e
* @return false|\stdClass
*/
public function onCreateAnnotation(EventInterface $e);
/**
* Register an annotation this parser will accept
*
* @param mixed $annotation
* @return void
*/
public function registerAnnotation($annotation);
/**
* Register multiple annotations this parser will accept
*
* @param array|\Traversable $annotations
* @return void
*/
public function registerAnnotations($annotations);
}

View File

@@ -0,0 +1,15 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Exception;
class BadMethodCallException extends \BadMethodCallException implements
ExceptionInterface
{
}

View File

@@ -0,0 +1,14 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Exception;
interface ExceptionInterface
{
}

View File

@@ -0,0 +1,15 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Exception;
class InvalidArgumentException extends \InvalidArgumentException implements
ExceptionInterface
{
}

View File

@@ -0,0 +1,14 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Exception;
class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}

View File

@@ -0,0 +1,124 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator;
use Traversable;
abstract class AbstractGenerator implements GeneratorInterface
{
/**
* Line feed to use in place of EOL
*/
const LINE_FEED = "\n";
/**
* @var bool
*/
protected $isSourceDirty = true;
/**
* @var int|string 4 spaces by default
*/
protected $indentation = ' ';
/**
* @var string
*/
protected $sourceContent = null;
/**
* @param array $options
*/
public function __construct($options = array())
{
if ($options) {
$this->setOptions($options);
}
}
/**
* @param bool $isSourceDirty
* @return AbstractGenerator
*/
public function setSourceDirty($isSourceDirty = true)
{
$this->isSourceDirty = (bool) $isSourceDirty;
return $this;
}
/**
* @return bool
*/
public function isSourceDirty()
{
return $this->isSourceDirty;
}
/**
* @param string $indentation
* @return AbstractGenerator
*/
public function setIndentation($indentation)
{
$this->indentation = (string) $indentation;
return $this;
}
/**
* @return string
*/
public function getIndentation()
{
return $this->indentation;
}
/**
* @param string $sourceContent
* @return AbstractGenerator
*/
public function setSourceContent($sourceContent)
{
$this->sourceContent = (string) $sourceContent;
return $this;
}
/**
* @return string
*/
public function getSourceContent()
{
return $this->sourceContent;
}
/**
* @param array|Traversable $options
* @throws Exception\InvalidArgumentException
* @return AbstractGenerator
*/
public function setOptions($options)
{
if (!is_array($options) && !$options instanceof Traversable) {
throw new Exception\InvalidArgumentException(sprintf(
'%s expects an array or Traversable object; received "%s"',
__METHOD__,
(is_object($options) ? get_class($options) : gettype($options))
));
}
foreach ($options as $optionName => $optionValue) {
$methodName = 'set' . $optionName;
if (method_exists($this, $methodName)) {
$this->{$methodName}($optionValue);
}
}
return $this;
}
}

View File

@@ -0,0 +1,224 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator;
abstract class AbstractMemberGenerator extends AbstractGenerator
{
/**#@+
* @const int Flags for construction usage
*/
const FLAG_ABSTRACT = 0x01;
const FLAG_FINAL = 0x02;
const FLAG_STATIC = 0x04;
const FLAG_PUBLIC = 0x10;
const FLAG_PROTECTED = 0x20;
const FLAG_PRIVATE = 0x40;
/**#@-*/
/**#@+
* @param const string
*/
const VISIBILITY_PUBLIC = 'public';
const VISIBILITY_PROTECTED = 'protected';
const VISIBILITY_PRIVATE = 'private';
/**#@-*/
/**
* @var DocBlockGenerator
*/
protected $docBlock = null;
/**
* @var string
*/
protected $name = null;
/**
* @var int
*/
protected $flags = self::FLAG_PUBLIC;
/**
* @param int|array $flags
* @return AbstractMemberGenerator
*/
public function setFlags($flags)
{
if (is_array($flags)) {
$flagsArray = $flags;
$flags = 0x00;
foreach ($flagsArray as $flag) {
$flags |= $flag;
}
}
// check that visibility is one of three
$this->flags = $flags;
return $this;
}
/**
* @param int $flag
* @return AbstractMemberGenerator
*/
public function addFlag($flag)
{
$this->setFlags($this->flags | $flag);
return $this;
}
/**
* @param int $flag
* @return AbstractMemberGenerator
*/
public function removeFlag($flag)
{
$this->setFlags($this->flags & ~$flag);
return $this;
}
/**
* @param bool $isAbstract
* @return AbstractMemberGenerator
*/
public function setAbstract($isAbstract)
{
return (($isAbstract) ? $this->addFlag(self::FLAG_ABSTRACT) : $this->removeFlag(self::FLAG_ABSTRACT));
}
/**
* @return bool
*/
public function isAbstract()
{
return (bool) ($this->flags & self::FLAG_ABSTRACT);
}
/**
* @param bool $isFinal
* @return AbstractMemberGenerator
*/
public function setFinal($isFinal)
{
return (($isFinal) ? $this->addFlag(self::FLAG_FINAL) : $this->removeFlag(self::FLAG_FINAL));
}
/**
* @return bool
*/
public function isFinal()
{
return (bool) ($this->flags & self::FLAG_FINAL);
}
/**
* @param bool $isStatic
* @return AbstractMemberGenerator
*/
public function setStatic($isStatic)
{
return (($isStatic) ? $this->addFlag(self::FLAG_STATIC) : $this->removeFlag(self::FLAG_STATIC));
}
/**
* @return bool
*/
public function isStatic()
{
return (bool) ($this->flags & self::FLAG_STATIC); // is FLAG_STATIC in flags
}
/**
* @param string $visibility
* @return AbstractMemberGenerator
*/
public function setVisibility($visibility)
{
switch ($visibility) {
case self::VISIBILITY_PUBLIC:
$this->removeFlag(self::FLAG_PRIVATE | self::FLAG_PROTECTED); // remove both
$this->addFlag(self::FLAG_PUBLIC);
break;
case self::VISIBILITY_PROTECTED:
$this->removeFlag(self::FLAG_PUBLIC | self::FLAG_PRIVATE); // remove both
$this->addFlag(self::FLAG_PROTECTED);
break;
case self::VISIBILITY_PRIVATE:
$this->removeFlag(self::FLAG_PUBLIC | self::FLAG_PROTECTED); // remove both
$this->addFlag(self::FLAG_PRIVATE);
break;
}
return $this;
}
/**
* @return string
*/
public function getVisibility()
{
switch (true) {
case ($this->flags & self::FLAG_PROTECTED):
return self::VISIBILITY_PROTECTED;
case ($this->flags & self::FLAG_PRIVATE):
return self::VISIBILITY_PRIVATE;
default:
return self::VISIBILITY_PUBLIC;
}
}
/**
* @param string $name
* @return AbstractMemberGenerator
*/
public function setName($name)
{
$this->name = (string) $name;
return $this;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @param DocBlockGenerator|string $docBlock
* @throws Exception\InvalidArgumentException
* @return AbstractMemberGenerator
*/
public function setDocBlock($docBlock)
{
if (is_string($docBlock)) {
$docBlock = new DocBlockGenerator($docBlock);
} elseif (!$docBlock instanceof DocBlockGenerator) {
throw new Exception\InvalidArgumentException(sprintf(
'%s is expecting either a string, array or an instance of %s\DocBlockGenerator',
__METHOD__,
__NAMESPACE__
));
}
$this->docBlock = $docBlock;
return $this;
}
/**
* @return DocBlockGenerator
*/
public function getDocBlock()
{
return $this->docBlock;
}
}

View File

@@ -0,0 +1,44 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator;
class BodyGenerator extends AbstractGenerator
{
/**
* @var string
*/
protected $content = null;
/**
* @param string $content
* @return BodyGenerator
*/
public function setContent($content)
{
$this->content = (string) $content;
return $this;
}
/**
* @return string
*/
public function getContent()
{
return $this->content;
}
/**
* @return string
*/
public function generate()
{
return $this->getContent();
}
}

View File

@@ -0,0 +1,987 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator;
use Zend\Code\Reflection\ClassReflection;
class ClassGenerator extends AbstractGenerator
{
const OBJECT_TYPE = "class";
const FLAG_ABSTRACT = 0x01;
const FLAG_FINAL = 0x02;
/**
* @var FileGenerator
*/
protected $containingFileGenerator = null;
/**
* @var string
*/
protected $namespaceName = null;
/**
* @var DocBlockGenerator
*/
protected $docBlock = null;
/**
* @var string
*/
protected $name = null;
/**
* @var bool
*/
protected $flags = 0x00;
/**
* @var string
*/
protected $extendedClass = null;
/**
* @var array Array of string names
*/
protected $implementedInterfaces = array();
/**
* @var PropertyGenerator[] Array of properties
*/
protected $properties = array();
/**
* @var PropertyGenerator[] Array of constants
*/
protected $constants = array();
/**
* @var MethodGenerator[] Array of methods
*/
protected $methods = array();
/**
* @var TraitUsageGenerator Object to encapsulate trait usage logic
*/
protected $traitUsageGenerator;
/**
* Build a Code Generation Php Object from a Class Reflection
*
* @param ClassReflection $classReflection
* @return ClassGenerator
*/
public static function fromReflection(ClassReflection $classReflection)
{
$cg = new static($classReflection->getName());
$cg->setSourceContent($cg->getSourceContent());
$cg->setSourceDirty(false);
if ($classReflection->getDocComment() != '') {
$cg->setDocBlock(DocBlockGenerator::fromReflection($classReflection->getDocBlock()));
}
$cg->setAbstract($classReflection->isAbstract());
// set the namespace
if ($classReflection->inNamespace()) {
$cg->setNamespaceName($classReflection->getNamespaceName());
}
/* @var \Zend\Code\Reflection\ClassReflection $parentClass */
$parentClass = $classReflection->getParentClass();
$interfaces = $classReflection->getInterfaces();
if ($parentClass) {
$cg->setExtendedClass($parentClass->getName());
$interfaces = array_diff($interfaces, $parentClass->getInterfaces());
}
$interfaceNames = array();
foreach ($interfaces as $interface) {
/* @var \Zend\Code\Reflection\ClassReflection $interface */
$interfaceNames[] = $interface->getName();
}
$cg->setImplementedInterfaces($interfaceNames);
$properties = array();
foreach ($classReflection->getProperties() as $reflectionProperty) {
if ($reflectionProperty->getDeclaringClass()->getName() == $classReflection->getName()) {
$properties[] = PropertyGenerator::fromReflection($reflectionProperty);
}
}
$cg->addProperties($properties);
$constants = array();
foreach ($classReflection->getConstants() as $name => $value) {
$constants[] = array(
'name' => $name,
'value' => $value
);
}
$cg->addConstants($constants);
$methods = array();
foreach ($classReflection->getMethods() as $reflectionMethod) {
$className = ($cg->getNamespaceName()) ? $cg->getNamespaceName() . "\\" . $cg->getName() : $cg->getName();
if ($reflectionMethod->getDeclaringClass()->getName() == $className) {
$methods[] = MethodGenerator::fromReflection($reflectionMethod);
}
}
$cg->addMethods($methods);
return $cg;
}
/**
* Generate from array
*
* @configkey name string [required] Class Name
* @configkey filegenerator FileGenerator File generator that holds this class
* @configkey namespacename string The namespace for this class
* @configkey docblock string The docblock information
* @configkey flags int Flags, one of ClassGenerator::FLAG_ABSTRACT ClassGenerator::FLAG_FINAL
* @configkey extendedclass string Class which this class is extending
* @configkey implementedinterfaces
* @configkey properties
* @configkey methods
*
* @throws Exception\InvalidArgumentException
* @param array $array
* @return ClassGenerator
*/
public static function fromArray(array $array)
{
if (!isset($array['name'])) {
throw new Exception\InvalidArgumentException(
'Class generator requires that a name is provided for this object'
);
}
$cg = new static($array['name']);
foreach ($array as $name => $value) {
// normalize key
switch (strtolower(str_replace(array('.', '-', '_'), '', $name))) {
case 'containingfile':
$cg->setContainingFileGenerator($value);
break;
case 'namespacename':
$cg->setNamespaceName($value);
break;
case 'docblock':
$docBlock = ($value instanceof DocBlockGenerator) ? $value : DocBlockGenerator::fromArray($value);
$cg->setDocBlock($docBlock);
break;
case 'flags':
$cg->setFlags($value);
break;
case 'extendedclass':
$cg->setExtendedClass($value);
break;
case 'implementedinterfaces':
$cg->setImplementedInterfaces($value);
break;
case 'properties':
$cg->addProperties($value);
break;
case 'methods':
$cg->addMethods($value);
break;
}
}
return $cg;
}
/**
* @param string $name
* @param string $namespaceName
* @param array|string $flags
* @param string $extends
* @param array $interfaces
* @param array $properties
* @param array $methods
* @param DocBlockGenerator $docBlock
*/
public function __construct(
$name = null,
$namespaceName = null,
$flags = null,
$extends = null,
$interfaces = array(),
$properties = array(),
$methods = array(),
$docBlock = null
) {
$this->traitUsageGenerator = new TraitUsageGenerator($this);
if ($name !== null) {
$this->setName($name);
}
if ($namespaceName !== null) {
$this->setNamespaceName($namespaceName);
}
if ($flags !== null) {
$this->setFlags($flags);
}
if ($properties !== array()) {
$this->addProperties($properties);
}
if ($extends !== null) {
$this->setExtendedClass($extends);
}
if (is_array($interfaces)) {
$this->setImplementedInterfaces($interfaces);
}
if ($methods !== array()) {
$this->addMethods($methods);
}
if ($docBlock !== null) {
$this->setDocBlock($docBlock);
}
}
/**
* @param string $name
* @return ClassGenerator
*/
public function setName($name)
{
if (strstr($name, '\\')) {
$namespace = substr($name, 0, strrpos($name, '\\'));
$name = substr($name, strrpos($name, '\\') + 1);
$this->setNamespaceName($namespace);
}
$this->name = $name;
return $this;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @param string $namespaceName
* @return ClassGenerator
*/
public function setNamespaceName($namespaceName)
{
$this->namespaceName = $namespaceName;
return $this;
}
/**
* @return string
*/
public function getNamespaceName()
{
return $this->namespaceName;
}
/**
* @param FileGenerator $fileGenerator
* @return ClassGenerator
*/
public function setContainingFileGenerator(FileGenerator $fileGenerator)
{
$this->containingFileGenerator = $fileGenerator;
return $this;
}
/**
* @return FileGenerator
*/
public function getContainingFileGenerator()
{
return $this->containingFileGenerator;
}
/**
* @param DocBlockGenerator $docBlock
* @return ClassGenerator
*/
public function setDocBlock(DocBlockGenerator $docBlock)
{
$this->docBlock = $docBlock;
return $this;
}
/**
* @return DocBlockGenerator
*/
public function getDocBlock()
{
return $this->docBlock;
}
/**
* @param array|string $flags
* @return ClassGenerator
*/
public function setFlags($flags)
{
if (is_array($flags)) {
$flagsArray = $flags;
$flags = 0x00;
foreach ($flagsArray as $flag) {
$flags |= $flag;
}
}
// check that visibility is one of three
$this->flags = $flags;
return $this;
}
/**
* @param string $flag
* @return ClassGenerator
*/
public function addFlag($flag)
{
$this->setFlags($this->flags | $flag);
return $this;
}
/**
* @param string $flag
* @return ClassGenerator
*/
public function removeFlag($flag)
{
$this->setFlags($this->flags & ~$flag);
return $this;
}
/**
* @param bool $isAbstract
* @return ClassGenerator
*/
public function setAbstract($isAbstract)
{
return (($isAbstract) ? $this->addFlag(self::FLAG_ABSTRACT) : $this->removeFlag(self::FLAG_ABSTRACT));
}
/**
* @return bool
*/
public function isAbstract()
{
return (bool) ($this->flags & self::FLAG_ABSTRACT);
}
/**
* @param bool $isFinal
* @return ClassGenerator
*/
public function setFinal($isFinal)
{
return (($isFinal) ? $this->addFlag(self::FLAG_FINAL) : $this->removeFlag(self::FLAG_FINAL));
}
/**
* @return bool
*/
public function isFinal()
{
return ($this->flags & self::FLAG_FINAL);
}
/**
* @param string $extendedClass
* @return ClassGenerator
*/
public function setExtendedClass($extendedClass)
{
$this->extendedClass = $extendedClass;
return $this;
}
/**
* @return string
*/
public function getExtendedClass()
{
return $this->extendedClass;
}
/**
* @param array $implementedInterfaces
* @return ClassGenerator
*/
public function setImplementedInterfaces(array $implementedInterfaces)
{
$this->implementedInterfaces = $implementedInterfaces;
return $this;
}
/**
* @return array
*/
public function getImplementedInterfaces()
{
return $this->implementedInterfaces;
}
/**
* @param string $constantName
*
* @return PropertyGenerator|false
*/
public function getConstant($constantName)
{
if (isset($this->constants[$constantName])) {
return $this->constants[$constantName];
}
return false;
}
/**
* @return PropertyGenerator[] indexed by constant name
*/
public function getConstants()
{
return $this->constants;
}
/**
* @param string $constantName
* @return bool
*/
public function hasConstant($constantName)
{
return isset($this->constants[$constantName]);
}
/**
* Add constant from PropertyGenerator
*
* @param PropertyGenerator $constant
* @throws Exception\InvalidArgumentException
* @return ClassGenerator
*/
public function addConstantFromGenerator(PropertyGenerator $constant)
{
$constantName = $constant->getName();
if (isset($this->constants[$constantName])) {
throw new Exception\InvalidArgumentException(sprintf(
'A constant by name %s already exists in this class.',
$constantName
));
}
if (! $constant->isConst()) {
throw new Exception\InvalidArgumentException(sprintf(
'The value %s is not defined as a constant.',
$constantName
));
}
$this->constants[$constantName] = $constant;
return $this;
}
/**
* Add Constant
*
* @param string $name
* @param string $value
* @throws Exception\InvalidArgumentException
* @return ClassGenerator
*/
public function addConstant($name, $value)
{
if (!is_string($name)) {
throw new Exception\InvalidArgumentException(sprintf(
'%s expects string for name',
__METHOD__
));
}
if (empty($value) || !is_string($value)) {
throw new Exception\InvalidArgumentException(sprintf(
'%s expects value for constant, value must be a string',
__METHOD__
));
}
return $this->addConstantFromGenerator(new PropertyGenerator($name, $value, PropertyGenerator::FLAG_CONSTANT));
}
/**
* @param PropertyGenerator[]|array[] $constants
*
* @return ClassGenerator
*/
public function addConstants(array $constants)
{
foreach ($constants as $constant) {
if ($constant instanceof PropertyGenerator) {
$this->addPropertyFromGenerator($constant);
} else {
if (is_array($constant)) {
call_user_func_array(array($this, 'addConstant'), $constant);
}
}
}
return $this;
}
/**
* @param array $properties
* @return ClassGenerator
*/
public function addProperties(array $properties)
{
foreach ($properties as $property) {
if ($property instanceof PropertyGenerator) {
$this->addPropertyFromGenerator($property);
} else {
if (is_string($property)) {
$this->addProperty($property);
} elseif (is_array($property)) {
call_user_func_array(array($this, 'addProperty'), $property);
}
}
}
return $this;
}
/**
* Add Property from scalars
*
* @param string $name
* @param string|array $defaultValue
* @param int $flags
* @throws Exception\InvalidArgumentException
* @return ClassGenerator
*/
public function addProperty($name, $defaultValue = null, $flags = PropertyGenerator::FLAG_PUBLIC)
{
if (!is_string($name)) {
throw new Exception\InvalidArgumentException(sprintf(
'%s::%s expects string for name',
get_class($this),
__FUNCTION__
));
}
// backwards compatibility
// @todo remove this on next major version
if ($flags === PropertyGenerator::FLAG_CONSTANT) {
return $this->addConstant($name, $defaultValue);
}
return $this->addPropertyFromGenerator(new PropertyGenerator($name, $defaultValue, $flags));
}
/**
* Add property from PropertyGenerator
*
* @param PropertyGenerator $property
* @throws Exception\InvalidArgumentException
* @return ClassGenerator
*/
public function addPropertyFromGenerator(PropertyGenerator $property)
{
$propertyName = $property->getName();
if (isset($this->properties[$propertyName])) {
throw new Exception\InvalidArgumentException(sprintf(
'A property by name %s already exists in this class.',
$propertyName
));
}
// backwards compatibility
// @todo remove this on next major version
if ($property->isConst()) {
return $this->addConstantFromGenerator($property);
}
$this->properties[$propertyName] = $property;
return $this;
}
/**
* @return PropertyGenerator[]
*/
public function getProperties()
{
return $this->properties;
}
/**
* @param string $propertyName
* @return PropertyGenerator|false
*/
public function getProperty($propertyName)
{
foreach ($this->getProperties() as $property) {
if ($property->getName() == $propertyName) {
return $property;
}
}
return false;
}
/**
* Add a class to "use" classes
*
* @param string $use
* @param string|null $useAlias
* @return ClassGenerator
*/
public function addUse($use, $useAlias = null)
{
$this->traitUsageGenerator->addUse($use, $useAlias);
return $this;
}
/**
* Returns the "use" classes
*
* @return array
*/
public function getUses()
{
return $this->traitUsageGenerator->getUses();
}
/**
* @param string $propertyName
* @return bool
*/
public function hasProperty($propertyName)
{
return isset($this->properties[$propertyName]);
}
/**
* @param array $methods
* @return ClassGenerator
*/
public function addMethods(array $methods)
{
foreach ($methods as $method) {
if ($method instanceof MethodGenerator) {
$this->addMethodFromGenerator($method);
} else {
if (is_string($method)) {
$this->addMethod($method);
} elseif (is_array($method)) {
call_user_func_array(array($this, 'addMethod'), $method);
}
}
}
return $this;
}
/**
* Add Method from scalars
*
* @param string $name
* @param array $parameters
* @param int $flags
* @param string $body
* @param string $docBlock
* @throws Exception\InvalidArgumentException
* @return ClassGenerator
*/
public function addMethod(
$name = null,
array $parameters = array(),
$flags = MethodGenerator::FLAG_PUBLIC,
$body = null,
$docBlock = null
) {
if (!is_string($name)) {
throw new Exception\InvalidArgumentException(sprintf(
'%s::%s expects string for name',
get_class($this),
__FUNCTION__
));
}
return $this->addMethodFromGenerator(new MethodGenerator($name, $parameters, $flags, $body, $docBlock));
}
/**
* Add Method from MethodGenerator
*
* @param MethodGenerator $method
* @throws Exception\InvalidArgumentException
* @return ClassGenerator
*/
public function addMethodFromGenerator(MethodGenerator $method)
{
$methodName = $method->getName();
if ($this->hasMethod($methodName)) {
throw new Exception\InvalidArgumentException(sprintf(
'A method by name %s already exists in this class.',
$methodName
));
}
$this->methods[strtolower($methodName)] = $method;
return $this;
}
/**
* @return MethodGenerator[]
*/
public function getMethods()
{
return $this->methods;
}
/**
* @param string $methodName
* @return MethodGenerator|false
*/
public function getMethod($methodName)
{
return $this->hasMethod($methodName) ? $this->methods[strtolower($methodName)] : false;
}
/**
* @param string $methodName
* @return ClassGenerator
*/
public function removeMethod($methodName)
{
if ($this->hasMethod($methodName)) {
unset($this->methods[strtolower($methodName)]);
}
return $this;
}
/**
* @param string $methodName
* @return bool
*/
public function hasMethod($methodName)
{
return isset($this->methods[strtolower($methodName)]);
}
/**
* @inherit Zend\Code\Generator\TraitUsageInterface
*/
public function addTrait($trait)
{
$this->traitUsageGenerator->addTrait($trait);
return $this;
}
/**
* @inherit Zend\Code\Generator\TraitUsageInterface
*/
public function addTraits(array $traits)
{
$this->traitUsageGenerator->addTraits($traits);
return $this;
}
/**
* @inherit Zend\Code\Generator\TraitUsageInterface
*/
public function hasTrait($traitName)
{
return $this->traitUsageGenerator->hasTrait($traitName);
}
/**
* @inherit Zend\Code\Generator\TraitUsageInterface
*/
public function getTraits()
{
return $this->traitUsageGenerator->getTraits();
}
/**
* @inherit Zend\Code\Generator\TraitUsageInterface
*/
public function removeTrait($traitName)
{
return $this->traitUsageGenerator->removeTrait($traitName);
}
/**
* @inherit Zend\Code\Generator\TraitUsageInterface
*/
public function addTraitAlias($method, $alias, $visibility = null)
{
$this->traitUsageGenerator->addTraitAlias($method, $alias, $visibility);
return $this;
}
/**
* @inherit Zend\Code\Generator\TraitUsageInterface
*/
public function getTraitAliases()
{
return $this->traitUsageGenerator->getTraitAliases();
}
/**
* @inherit Zend\Code\Generator\TraitUsageInterface
*/
public function addTraitOverride($method, $traitsToReplace)
{
$this->traitUsageGenerator->addTraitOverride($method, $traitsToReplace);
return $this;
}
/**
* @inherit Zend\Code\Generator\TraitUsageInterface
*/
public function removeTraitOverride($method, $overridesToRemove = null)
{
$this->traitUsageGenerator->removeTraitOverride($method, $overridesToRemove);
return $this;
}
/**
* @inherit Zend\Code\Generator\TraitUsageInterface
*/
public function getTraitOverrides()
{
return $this->traitUsageGenerator->getTraitOverrides();
}
/**
* @return bool
*/
public function isSourceDirty()
{
if (($docBlock = $this->getDocBlock()) && $docBlock->isSourceDirty()) {
return true;
}
foreach ($this->getProperties() as $property) {
if ($property->isSourceDirty()) {
return true;
}
}
foreach ($this->getMethods() as $method) {
if ($method->isSourceDirty()) {
return true;
}
}
return parent::isSourceDirty();
}
/**
* @inherit Zend\Code\Generator\GeneratorInterface
*/
public function generate()
{
if (!$this->isSourceDirty()) {
$output = $this->getSourceContent();
if (!empty($output)) {
return $output;
}
}
$indent = $this->getIndentation();
$output = '';
if (null !== ($namespace = $this->getNamespaceName())) {
$output .= 'namespace ' . $namespace . ';' . self::LINE_FEED . self::LINE_FEED;
}
$uses = $this->getUses();
if (!empty($uses)) {
foreach ($uses as $use) {
$output .= 'use ' . $use . ';' . self::LINE_FEED;
}
$output .= self::LINE_FEED;
}
if (null !== ($docBlock = $this->getDocBlock())) {
$docBlock->setIndentation('');
$output .= $docBlock->generate();
}
if ($this->isAbstract()) {
$output .= 'abstract ';
} elseif ($this->isFinal()) {
$output .= 'final ';
}
$output .= static::OBJECT_TYPE . ' ' . $this->getName();
if (!empty($this->extendedClass)) {
$output .= ' extends ' . $this->extendedClass;
}
$implemented = $this->getImplementedInterfaces();
if (!empty($implemented)) {
$output .= ' implements ' . implode(', ', $implemented);
}
$output .= self::LINE_FEED . '{' . self::LINE_FEED . self::LINE_FEED;
$output .= $this->traitUsageGenerator->generate();
$constants = $this->getConstants();
foreach ($constants as $constant) {
$output .= $constant->generate() . self::LINE_FEED . self::LINE_FEED;
}
$properties = $this->getProperties();
foreach ($properties as $property) {
$output .= $property->generate() . self::LINE_FEED . self::LINE_FEED;
}
$methods = $this->getMethods();
foreach ($methods as $method) {
$output .= $method->generate() . self::LINE_FEED;
}
$output .= self::LINE_FEED . '}' . self::LINE_FEED;
return $output;
}
}

View File

@@ -0,0 +1,50 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator\DocBlock;
use Zend\Code\Generator\DocBlock\Tag\GenericTag;
use Zend\Code\Reflection\DocBlock\Tag\TagInterface as ReflectionTagInterface;
/**
* @deprecated Deprecated in 2.3. Use GenericTag instead
*/
class Tag extends GenericTag
{
/**
* @param ReflectionTagInterface $reflectionTag
* @return Tag
* @deprecated Deprecated in 2.3. Use TagManager::createTagFromReflection() instead
*/
public static function fromReflection(ReflectionTagInterface $reflectionTag)
{
$tagManager = new TagManager();
$tagManager->initializeDefaultTags();
return $tagManager->createTagFromReflection($reflectionTag);
}
/**
* @param string $description
* @return Tag
* @deprecated Deprecated in 2.3. Use GenericTag::setContent() instead
*/
public function setDescription($description)
{
return $this->setContent($description);
}
/**
* @return string
* @deprecated Deprecated in 2.3. Use GenericTag::getContent() instead
*/
public function getDescription()
{
return $this->getContent();
}
}

View File

@@ -0,0 +1,96 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator\DocBlock\Tag;
use Zend\Code\Generator\AbstractGenerator;
/**
* This abstract class can be used as parent for all tags
* that use a type part in their content.
* @see http://www.phpdoc.org/docs/latest/for-users/phpdoc/types.html
*/
abstract class AbstractTypeableTag extends AbstractGenerator
{
/**
* @var string
*/
protected $description = null;
/**
* @var array
*/
protected $types = array();
/**
* @param array $types
* @param string $description
*/
public function __construct($types = array(), $description = null)
{
if (!empty($types)) {
$this->setTypes($types);
}
if (!empty($description)) {
$this->setDescription($description);
}
}
/**
* @param string $description
* @return ReturnTag
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Array of types or string with types delimited by pipe (|)
* e.g. array('int', 'null') or "int|null"
*
* @param array|string $types
* @return ReturnTag
*/
public function setTypes($types)
{
if (is_string($types)) {
$types = explode('|', $types);
}
$this->types = $types;
return $this;
}
/**
* @return array
*/
public function getTypes()
{
return $this->types;
}
/**
* @param string $delimiter
* @return string
*/
public function getTypesAsString($delimiter = '|')
{
return implode($delimiter, $this->types);
}
}

View File

@@ -0,0 +1,110 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator\DocBlock\Tag;
use Zend\Code\Generator\AbstractGenerator;
use Zend\Code\Generator\DocBlock\TagManager;
use Zend\Code\Reflection\DocBlock\Tag\TagInterface as ReflectionTagInterface;
class AuthorTag extends AbstractGenerator implements TagInterface
{
/**
* @var string
*/
protected $authorName = null;
/**
* @var string
*/
protected $authorEmail = null;
/**
* @param string $authorName
* @param string $authorEmail
*/
public function __construct($authorName = null, $authorEmail = null)
{
if (!empty($authorName)) {
$this->setAuthorName($authorName);
}
if (!empty($authorEmail)) {
$this->setAuthorEmail($authorEmail);
}
}
/**
* @param ReflectionTagInterface $reflectionTag
* @return ReturnTag
* @deprecated Deprecated in 2.3. Use TagManager::createTagFromReflection() instead
*/
public static function fromReflection(ReflectionTagInterface $reflectionTag)
{
$tagManager = new TagManager();
$tagManager->initializeDefaultTags();
return $tagManager->createTagFromReflection($reflectionTag);
}
/**
* @return string
*/
public function getName()
{
return 'author';
}
/**
* @param string $authorEmail
* @return AuthorTag
*/
public function setAuthorEmail($authorEmail)
{
$this->authorEmail = $authorEmail;
return $this;
}
/**
* @return string
*/
public function getAuthorEmail()
{
return $this->authorEmail;
}
/**
* @param string $authorName
* @return AuthorTag
*/
public function setAuthorName($authorName)
{
$this->authorName = $authorName;
return $this;
}
/**
* @return string
*/
public function getAuthorName()
{
return $this->authorName;
}
/**
* @return string
*/
public function generate()
{
$output = '@author'
. ((!empty($this->authorName)) ? ' ' . $this->authorName : '')
. ((!empty($this->authorEmail)) ? ' <' . $this->authorEmail . '>' : '');
return $output;
}
}

View File

@@ -0,0 +1,88 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator\DocBlock\Tag;
use Zend\Code\Generator\AbstractGenerator;
use Zend\Code\Generic\Prototype\PrototypeGenericInterface;
class GenericTag extends AbstractGenerator implements TagInterface, PrototypeGenericInterface
{
/**
* @var string
*/
protected $name = null;
/**
* @var string
*/
protected $content = null;
/**
* @param string $name
* @param string $content
*/
public function __construct($name = null, $content = null)
{
if (!empty($name)) {
$this->setName($name);
}
if (!empty($content)) {
$this->setContent($content);
}
}
/**
* @param string $name
* @return GenericTag
*/
public function setName($name)
{
$this->name = ltrim($name, '@');
return $this;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @param string $content
* @return GenericTag
*/
public function setContent($content)
{
$this->content = $content;
return $this;
}
/**
* @return string
*/
public function getContent()
{
return $this->content;
}
/**
* @return string
*/
public function generate()
{
$output = '@' . $this->name
. ((!empty($this->content)) ? ' ' . $this->content : '');
return $output;
}
}

View File

@@ -0,0 +1,110 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator\DocBlock\Tag;
use Zend\Code\Generator\AbstractGenerator;
use Zend\Code\Generator\DocBlock\TagManager;
use Zend\Code\Reflection\DocBlock\Tag\TagInterface as ReflectionTagInterface;
class LicenseTag extends AbstractGenerator implements TagInterface
{
/**
* @var string
*/
protected $url = null;
/**
* @var string
*/
protected $licenseName = null;
/**
* @param string $url
* @param string $licenseName
*/
public function __construct($url = null, $licenseName = null)
{
if (!empty($url)) {
$this->setUrl($url);
}
if (!empty($licenseName)) {
$this->setLicenseName($licenseName);
}
}
/**
* @param ReflectionTagInterface $reflectionTag
* @return ReturnTag
* @deprecated Deprecated in 2.3. Use TagManager::createTagFromReflection() instead
*/
public static function fromReflection(ReflectionTagInterface $reflectionTag)
{
$tagManager = new TagManager();
$tagManager->initializeDefaultTags();
return $tagManager->createTagFromReflection($reflectionTag);
}
/**
* @return string
*/
public function getName()
{
return 'license';
}
/**
* @param string $url
* @return LicenseTag
*/
public function setUrl($url)
{
$this->url = $url;
return $this;
}
/**
* @return string
*/
public function getUrl()
{
return $this->url;
}
/**
* @param string $name
* @return LicenseTag
*/
public function setLicenseName($name)
{
$this->licenseName = $name;
return $this;
}
/**
* @return string
*/
public function getLicenseName()
{
return $this->licenseName;
}
/**
* @return string
*/
public function generate()
{
$output = '@license'
. ((!empty($this->url)) ? ' ' . $this->url : '')
. ((!empty($this->licenseName)) ? ' ' . $this->licenseName : '');
return $output;
}
}

View File

@@ -0,0 +1,98 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator\DocBlock\Tag;
class MethodTag extends AbstractTypeableTag implements TagInterface
{
/**
* @var string
*/
protected $methodName = null;
/**
* @var bool
*/
protected $isStatic = false;
/**
* @param string $methodName
* @param array $types
* @param string $description
* @param bool $isStatic
*/
public function __construct($methodName = null, $types = array(), $description = null, $isStatic = false)
{
if (!empty($methodName)) {
$this->setMethodName($methodName);
}
$this->setIsStatic((bool) $isStatic);
parent::__construct($types, $description);
}
/**
* @return string
*/
public function getName()
{
return 'method';
}
/**
* @param boolean $isStatic
* @return MethodTag
*/
public function setIsStatic($isStatic)
{
$this->isStatic = $isStatic;
return $this;
}
/**
* @return boolean
*/
public function isStatic()
{
return $this->isStatic;
}
/**
* @param string $methodName
* @return MethodTag
*/
public function setMethodName($methodName)
{
$this->methodName = rtrim($methodName, ')(');
return $this;
}
/**
* @return string
*/
public function getMethodName()
{
return $this->methodName;
}
/**
* @return string
*/
public function generate()
{
$output = '@method'
. (($this->isStatic) ? ' static' : '')
. ((!empty($this->types)) ? ' ' . $this->getTypesAsString() : '')
. ((!empty($this->methodName)) ? ' ' . $this->methodName . '()' : '')
. ((!empty($this->description)) ? ' ' . $this->description : '');
return $output;
}
}

View File

@@ -0,0 +1,124 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator\DocBlock\Tag;
use Zend\Code\Generator\DocBlock\TagManager;
use Zend\Code\Reflection\DocBlock\Tag\TagInterface as ReflectionTagInterface;
class ParamTag extends AbstractTypeableTag implements TagInterface
{
/**
* @var string
*/
protected $variableName = null;
/**
* @param string $variableName
* @param array $types
* @param string $description
*/
public function __construct($variableName = null, $types = array(), $description = null)
{
if (!empty($variableName)) {
$this->setVariableName($variableName);
}
parent::__construct($types, $description);
}
/**
* @param ReflectionTagInterface $reflectionTag
* @return ReturnTag
* @deprecated Deprecated in 2.3. Use TagManager::createTagFromReflection() instead
*/
public static function fromReflection(ReflectionTagInterface $reflectionTag)
{
$tagManager = new TagManager();
$tagManager->initializeDefaultTags();
return $tagManager->createTagFromReflection($reflectionTag);
}
/**
* @return string
*/
public function getName()
{
return 'param';
}
/**
* @param string $variableName
* @return ParamTag
*/
public function setVariableName($variableName)
{
$this->variableName = ltrim($variableName, '$');
return $this;
}
/**
* @return string
*/
public function getVariableName()
{
return $this->variableName;
}
/**
* @param string $datatype
* @return ReturnTag
* @deprecated Deprecated in 2.3. Use setTypes() instead
*/
public function setDatatype($datatype)
{
return $this->setTypes($datatype);
}
/**
* @return string
* @deprecated Deprecated in 2.3. Use getTypes() or getTypesAsString() instead
*/
public function getDatatype()
{
return $this->getTypesAsString();
}
/**
* @param string $paramName
* @return ParamTag
* @deprecated Deprecated in 2.3. Use setVariableName() instead
*/
public function setParamName($paramName)
{
return $this->setVariableName($paramName);
}
/**
* @return string
* @deprecated Deprecated in 2.3. Use getVariableName() instead
*/
public function getParamName()
{
return $this->getVariableName();
}
/**
* @return string
*/
public function generate()
{
$output = '@param'
. ((!empty($this->types)) ? ' ' . $this->getTypesAsString() : '')
. ((!empty($this->variableName)) ? ' $' . $this->variableName : '')
. ((!empty($this->description)) ? ' ' . $this->description : '');
return $output;
}
}

View File

@@ -0,0 +1,71 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator\DocBlock\Tag;
class PropertyTag extends AbstractTypeableTag implements TagInterface
{
/**
* @var string
*/
protected $propertyName = null;
/**
* @param string $propertyName
* @param array $types
* @param string $description
*/
public function __construct($propertyName = null, $types = array(), $description = null)
{
if (!empty($propertyName)) {
$this->setPropertyName($propertyName);
}
parent::__construct($types, $description);
}
/**
* @return string
*/
public function getName()
{
return 'property';
}
/**
* @param string $propertyName
* @return self
*/
public function setPropertyName($propertyName)
{
$this->propertyName = ltrim($propertyName, '$');
return $this;
}
/**
* @return string
*/
public function getPropertyName()
{
return $this->propertyName;
}
/**
* @return string
*/
public function generate()
{
$output = '@property'
. ((!empty($this->types)) ? ' ' . $this->getTypesAsString() : '')
. ((!empty($this->propertyName)) ? ' $' . $this->propertyName : '')
. ((!empty($this->description)) ? ' ' . $this->description : '');
return $output;
}
}

View File

@@ -0,0 +1,67 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator\DocBlock\Tag;
use Zend\Code\Generator\DocBlock\TagManager;
use Zend\Code\Reflection\DocBlock\Tag\TagInterface as ReflectionTagInterface;
class ReturnTag extends AbstractTypeableTag implements TagInterface
{
/**
* @param ReflectionTagInterface $reflectionTag
* @return ReturnTag
* @deprecated Deprecated in 2.3. Use TagManager::createTagFromReflection() instead
*/
public static function fromReflection(ReflectionTagInterface $reflectionTag)
{
$tagManager = new TagManager();
$tagManager->initializeDefaultTags();
return $tagManager->createTagFromReflection($reflectionTag);
}
/**
* @return string
*/
public function getName()
{
return 'return';
}
/**
* @param string $datatype
* @return ReturnTag
* @deprecated Deprecated in 2.3. Use setTypes() instead
*/
public function setDatatype($datatype)
{
return $this->setTypes($datatype);
}
/**
* @return string
* @deprecated Deprecated in 2.3. Use getTypes() or getTypesAsString() instead
*/
public function getDatatype()
{
return $this->getTypesAsString();
}
/**
* @return string
*/
public function generate()
{
$output = '@return '
. $this->getTypesAsString()
. ((!empty($this->description)) ? ' ' . $this->description : '');
return $output;
}
}

View File

@@ -0,0 +1,16 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator\DocBlock\Tag;
use Zend\Code\Generic\Prototype\PrototypeInterface;
interface TagInterface extends PrototypeInterface
{
}

View File

@@ -0,0 +1,33 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator\DocBlock\Tag;
class ThrowsTag extends AbstractTypeableTag implements TagInterface
{
/**
* @return string
*/
public function getName()
{
return 'throws';
}
/**
* @return string
*/
public function generate()
{
$output = '@throws'
. ((!empty($this->types)) ? ' ' . $this->getTypesAsString() : '')
. ((!empty($this->description)) ? ' ' . $this->description : '');
return $output;
}
}

View File

@@ -0,0 +1,69 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator\DocBlock;
use Zend\Code\Generator\DocBlock\Tag\TagInterface;
use Zend\Code\Generic\Prototype\PrototypeClassFactory;
use Zend\Code\Reflection\DocBlock\Tag\TagInterface as ReflectionTagInterface;
/**
* This class is used in DocBlockGenerator and creates the needed
* Tag classes depending on the tag. So for example an @author tag
* will trigger the creation of an AuthorTag class.
*
* If none of the classes is applicable, the GenericTag class will be
* created
*/
class TagManager extends PrototypeClassFactory
{
/**
* @return void
*/
public function initializeDefaultTags()
{
$this->addPrototype(new Tag\ParamTag());
$this->addPrototype(new Tag\ReturnTag());
$this->addPrototype(new Tag\MethodTag());
$this->addPrototype(new Tag\PropertyTag());
$this->addPrototype(new Tag\AuthorTag());
$this->addPrototype(new Tag\LicenseTag());
$this->addPrototype(new Tag\ThrowsTag());
$this->setGenericPrototype(new Tag\GenericTag());
}
/**
* @param ReflectionTagInterface $reflectionTag
* @return TagInterface
*/
public function createTagFromReflection(ReflectionTagInterface $reflectionTag)
{
$tagName = $reflectionTag->getName();
/* @var TagInterface $newTag */
$newTag = $this->getClonedPrototype($tagName);
// transport any properties via accessors and mutators from reflection to codegen object
$reflectionClass = new \ReflectionClass($reflectionTag);
foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
if (substr($method->getName(), 0, 3) == 'get') {
$propertyName = substr($method->getName(), 3);
if (method_exists($newTag, 'set' . $propertyName)) {
$newTag->{'set' . $propertyName}($reflectionTag->{'get' . $propertyName}());
}
} elseif (substr($method->getName(), 0, 2) == 'is') {
$propertyName = ucfirst($method->getName());
if (method_exists($newTag, 'set' . $propertyName)) {
$newTag->{'set' . $propertyName}($reflectionTag->{$method->getName()}());
}
}
}
return $newTag;
}
}

View File

@@ -0,0 +1,274 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator;
use Zend\Code\Generator\DocBlock\Tag;
use Zend\Code\Generator\DocBlock\Tag\TagInterface;
use Zend\Code\Generator\DocBlock\TagManager;
use Zend\Code\Reflection\DocBlockReflection;
class DocBlockGenerator extends AbstractGenerator
{
/**
* @var string
*/
protected $shortDescription = null;
/**
* @var string
*/
protected $longDescription = null;
/**
* @var array
*/
protected $tags = array();
/**
* @var string
*/
protected $indentation = '';
/**
* @var bool
*/
protected $wordwrap = true;
protected static $tagManager;
/**
* Build a DocBlock generator object from a reflection object
*
* @param DocBlockReflection $reflectionDocBlock
* @return DocBlockGenerator
*/
public static function fromReflection(DocBlockReflection $reflectionDocBlock)
{
$docBlock = new static();
$docBlock->setSourceContent($reflectionDocBlock->getContents());
$docBlock->setSourceDirty(false);
$docBlock->setShortDescription($reflectionDocBlock->getShortDescription());
$docBlock->setLongDescription($reflectionDocBlock->getLongDescription());
foreach ($reflectionDocBlock->getTags() as $tag) {
$docBlock->setTag(self::getTagManager()->createTagFromReflection($tag));
}
return $docBlock;
}
/**
* Generate from array
*
* @configkey shortdescription string The short description for this doc block
* @configkey longdescription string The long description for this doc block
* @configkey tags array
*
* @throws Exception\InvalidArgumentException
* @param array $array
* @return DocBlockGenerator
*/
public static function fromArray(array $array)
{
$docBlock = new static();
foreach ($array as $name => $value) {
// normalize key
switch (strtolower(str_replace(array('.', '-', '_'), '', $name))) {
case 'shortdescription':
$docBlock->setShortDescription($value);
break;
case 'longdescription':
$docBlock->setLongDescription($value);
break;
case 'tags':
$docBlock->setTags($value);
break;
}
}
return $docBlock;
}
protected static function getTagManager()
{
if (!isset(static::$tagManager)) {
static::$tagManager = new TagManager();
static::$tagManager->initializeDefaultTags();
}
return static::$tagManager;
}
/**
* @param string $shortDescription
* @param string $longDescription
* @param array $tags
*/
public function __construct($shortDescription = null, $longDescription = null, array $tags = array())
{
if ($shortDescription) {
$this->setShortDescription($shortDescription);
}
if ($longDescription) {
$this->setLongDescription($longDescription);
}
if (is_array($tags) && $tags) {
$this->setTags($tags);
}
}
/**
* @param string $shortDescription
* @return DocBlockGenerator
*/
public function setShortDescription($shortDescription)
{
$this->shortDescription = $shortDescription;
return $this;
}
/**
* @return string
*/
public function getShortDescription()
{
return $this->shortDescription;
}
/**
* @param string $longDescription
* @return DocBlockGenerator
*/
public function setLongDescription($longDescription)
{
$this->longDescription = $longDescription;
return $this;
}
/**
* @return string
*/
public function getLongDescription()
{
return $this->longDescription;
}
/**
* @param array $tags
* @return DocBlockGenerator
*/
public function setTags(array $tags)
{
foreach ($tags as $tag) {
$this->setTag($tag);
}
return $this;
}
/**
* @param array|TagInterface $tag
* @throws Exception\InvalidArgumentException
* @return DocBlockGenerator
*/
public function setTag($tag)
{
if (is_array($tag)) {
// use deprecated Tag class for backward compatiblity to old array-keys
$genericTag = new Tag();
$genericTag->setOptions($tag);
$tag = $genericTag;
} elseif (!$tag instanceof TagInterface) {
throw new Exception\InvalidArgumentException(sprintf(
'%s expects either an array of method options or an instance of %s\DocBlock\Tag\TagInterface',
__METHOD__,
__NAMESPACE__
));
}
$this->tags[] = $tag;
return $this;
}
/**
* @return TagInterface[]
*/
public function getTags()
{
return $this->tags;
}
/**
* @param bool $value
* @return DocBlockGenerator
*/
public function setWordWrap($value)
{
$this->wordwrap = (bool) $value;
return $this;
}
/**
* @return bool
*/
public function getWordWrap()
{
return $this->wordwrap;
}
/**
* @return string
*/
public function generate()
{
if (!$this->isSourceDirty()) {
return $this->docCommentize(trim($this->getSourceContent()));
}
$output = '';
if (null !== ($sd = $this->getShortDescription())) {
$output .= $sd . self::LINE_FEED . self::LINE_FEED;
}
if (null !== ($ld = $this->getLongDescription())) {
$output .= $ld . self::LINE_FEED . self::LINE_FEED;
}
/* @var $tag GeneratorInterface */
foreach ($this->getTags() as $tag) {
$output .= $tag->generate() . self::LINE_FEED;
}
return $this->docCommentize(trim($output));
}
/**
* @param string $content
* @return string
*/
protected function docCommentize($content)
{
$indent = $this->getIndentation();
$output = $indent . '/**' . self::LINE_FEED;
$content = $this->getWordWrap() == true ? wordwrap($content, 80, self::LINE_FEED) : $content;
$lines = explode(self::LINE_FEED, $content);
foreach ($lines as $line) {
$output .= $indent . ' *';
if ($line) {
$output .= " $line";
}
$output .= self::LINE_FEED;
}
$output .= $indent . ' */' . self::LINE_FEED;
return $output;
}
}

View File

@@ -0,0 +1,16 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator\Exception;
use Zend\Code\Exception\ExceptionInterface as Exception;
interface ExceptionInterface extends Exception
{
}

View File

@@ -0,0 +1,17 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator\Exception;
use Zend\Code\Exception;
class InvalidArgumentException extends Exception\InvalidArgumentException implements
ExceptionInterface
{
}

View File

@@ -0,0 +1,17 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator\Exception;
use Zend\Code\Exception;
class RuntimeException extends Exception\RuntimeException implements
ExceptionInterface
{
}

View File

@@ -0,0 +1,561 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator;
use Zend\Code\Reflection\Exception as ReflectionException;
use Zend\Code\Reflection\FileReflection;
class FileGenerator extends AbstractGenerator
{
/**
* @var string
*/
protected $filename = null;
/**
* @var DocBlockGenerator
*/
protected $docBlock = null;
/**
* @var array
*/
protected $requiredFiles = array();
/**
* @var string
*/
protected $namespace = null;
/**
* @var array
*/
protected $uses = array();
/**
* @var array
*/
protected $classes = array();
/**
* @var string
*/
protected $body = null;
/**
* Passes $options to {@link setOptions()}.
*
* @param array|\Traversable $options
*/
public function __construct($options = null)
{
if (null !== $options) {
$this->setOptions($options);
}
}
/**
* Use this if you intend on generating code generation objects based on the same file.
* This will keep previous changes to the file in tact during the same PHP process
*
* @param string $filePath
* @param bool $includeIfNotAlreadyIncluded
* @throws ReflectionException\InvalidArgumentException If file does not exists
* @throws ReflectionException\RuntimeException If file exists but is not included or required
* @return FileGenerator
*/
public static function fromReflectedFileName($filePath, $includeIfNotAlreadyIncluded = true)
{
$fileReflector = new FileReflection($filePath, $includeIfNotAlreadyIncluded);
$codeGenerator = static::fromReflection($fileReflector);
return $codeGenerator;
}
/**
* @param FileReflection $fileReflection
* @return FileGenerator
*/
public static function fromReflection(FileReflection $fileReflection)
{
$file = new static();
$file->setSourceContent($fileReflection->getContents());
$file->setSourceDirty(false);
$uses = $fileReflection->getUses();
foreach ($fileReflection->getClasses() as $class) {
$phpClass = ClassGenerator::fromReflection($class);
$phpClass->setContainingFileGenerator($file);
foreach ($uses as $fileUse) {
$phpClass->addUse($fileUse['use'], $fileUse['as']);
}
$file->setClass($phpClass);
}
$namespace = $fileReflection->getNamespace();
if ($namespace != '') {
$file->setNamespace($namespace);
}
if ($uses) {
$file->setUses($uses);
}
if (($fileReflection->getDocComment() != '')) {
$docBlock = $fileReflection->getDocBlock();
$file->setDocBlock(DocBlockGenerator::fromReflection($docBlock));
}
return $file;
}
/**
* @param array $values
* @return FileGenerator
*/
public static function fromArray(array $values)
{
$fileGenerator = new static;
foreach ($values as $name => $value) {
switch (strtolower(str_replace(array('.', '-', '_'), '', $name))) {
case 'filename':
$fileGenerator->setFilename($value);
continue;
case 'class':
$fileGenerator->setClass(($value instanceof ClassGenerator) ? $value : ClassGenerator::fromArray($value));
continue;
case 'requiredfiles':
$fileGenerator->setRequiredFiles($value);
continue;
default:
if (property_exists($fileGenerator, $name)) {
$fileGenerator->{$name} = $value;
} elseif (method_exists($fileGenerator, 'set' . $name)) {
$fileGenerator->{'set' . $name}($value);
}
}
}
return $fileGenerator;
}
/**
* @param DocBlockGenerator|array|string $docBlock
* @throws Exception\InvalidArgumentException
* @return FileGenerator
*/
public function setDocBlock($docBlock)
{
if (is_string($docBlock)) {
$docBlock = array('shortDescription' => $docBlock);
}
if (is_array($docBlock)) {
$docBlock = new DocBlockGenerator($docBlock);
} elseif (!$docBlock instanceof DocBlockGenerator) {
throw new Exception\InvalidArgumentException(sprintf(
'%s is expecting either a string, array or an instance of %s\DocBlockGenerator',
__METHOD__,
__NAMESPACE__
));
}
$this->docBlock = $docBlock;
return $this;
}
/**
* @return DocBlockGenerator
*/
public function getDocBlock()
{
return $this->docBlock;
}
/**
* @param array $requiredFiles
* @return FileGenerator
*/
public function setRequiredFiles(array $requiredFiles)
{
$this->requiredFiles = $requiredFiles;
return $this;
}
/**
* @return array
*/
public function getRequiredFiles()
{
return $this->requiredFiles;
}
/**
* @return string
*/
public function getNamespace()
{
return $this->namespace;
}
/**
* @param string $namespace
* @return FileGenerator
*/
public function setNamespace($namespace)
{
$this->namespace = (string) $namespace;
return $this;
}
/**
* Returns an array with the first element the use statement, second is the as part.
* If $withResolvedAs is set to true, there will be a third element that is the
* "resolved" as statement, as the second part is not required in use statements
*
* @param bool $withResolvedAs
* @return array
*/
public function getUses($withResolvedAs = false)
{
$uses = $this->uses;
if ($withResolvedAs) {
for ($useIndex = 0, $count = count($uses); $useIndex < $count; $useIndex++) {
if ($uses[$useIndex][1] == '') {
if (($lastSeparator = strrpos($uses[$useIndex][0], '\\')) !== false) {
$uses[$useIndex][2] = substr($uses[$useIndex][0], $lastSeparator + 1);
} else {
$uses[$useIndex][2] = $uses[$useIndex][0];
}
} else {
$uses[$useIndex][2] = $uses[$useIndex][1];
}
}
}
return $uses;
}
/**
* @param array $uses
* @return FileGenerator
*/
public function setUses(array $uses)
{
foreach ($uses as $use) {
$use = (array) $use;
if (array_key_exists('use', $use) && array_key_exists('as', $use)) {
$import = $use['use'];
$alias = $use['as'];
} elseif (count($use) == 2) {
list($import, $alias) = $use;
} else {
$import = current($use);
$alias = null;
}
$this->setUse($import, $alias);
}
return $this;
}
/**
* @param string $use
* @param null|string $as
* @return FileGenerator
*/
public function setUse($use, $as = null)
{
if (!in_array(array($use, $as), $this->uses)) {
$this->uses[] = array($use, $as);
}
return $this;
}
/**
* @param array $classes
* @return FileGenerator
*/
public function setClasses(array $classes)
{
foreach ($classes as $class) {
$this->setClass($class);
}
return $this;
}
/**
* @param string $name
* @return ClassGenerator
*/
public function getClass($name = null)
{
if ($name === null) {
reset($this->classes);
return current($this->classes);
}
return $this->classes[(string) $name];
}
/**
* @param array|string|ClassGenerator $class
* @throws Exception\InvalidArgumentException
* @return FileGenerator
*/
public function setClass($class)
{
if (is_array($class)) {
$class = ClassGenerator::fromArray($class);
} elseif (is_string($class)) {
$class = new ClassGenerator($class);
} elseif (!$class instanceof ClassGenerator) {
throw new Exception\InvalidArgumentException(sprintf(
'%s is expecting either a string, array or an instance of %s\ClassGenerator',
__METHOD__,
__NAMESPACE__
));
}
// @todo check for dup here
$className = $class->getName();
$this->classes[$className] = $class;
return $this;
}
/**
* @param string $filename
* @return FileGenerator
*/
public function setFilename($filename)
{
$this->filename = (string) $filename;
return $this;
}
/**
* @return string
*/
public function getFilename()
{
return $this->filename;
}
/**
* @return ClassGenerator[]
*/
public function getClasses()
{
return $this->classes;
}
/**
* @param string $body
* @return FileGenerator
*/
public function setBody($body)
{
$this->body = (string) $body;
return $this;
}
/**
* @return string
*/
public function getBody()
{
return $this->body;
}
/**
* @return bool
*/
public function isSourceDirty()
{
$docBlock = $this->getDocBlock();
if ($docBlock && $docBlock->isSourceDirty()) {
return true;
}
foreach ($this->classes as $class) {
if ($class->isSourceDirty()) {
return true;
}
}
return parent::isSourceDirty();
}
/**
* @return string
*/
public function generate()
{
if ($this->isSourceDirty() === false) {
return $this->sourceContent;
}
$output = '';
// @note body gets populated when FileGenerator created
// from a file. @see fromReflection and may also be set
// via FileGenerator::setBody
$body = $this->getBody();
// start with the body (if there), or open tag
if (preg_match('#(?:\s*)<\?php#', $body) == false) {
$output = '<?php' . self::LINE_FEED;
}
// if there are markers, put the body into the output
if (preg_match('#/\* Zend_Code_Generator_Php_File-(.*?)Marker:#m', $body)) {
$tokens = token_get_all($body);
foreach ($tokens as $token) {
if (is_array($token) && in_array($token[0], array(T_OPEN_TAG, T_COMMENT, T_DOC_COMMENT, T_WHITESPACE))
) {
$output .= $token[1];
}
}
$body = '';
}
// Add file DocBlock, if any
if (null !== ($docBlock = $this->getDocBlock())) {
$docBlock->setIndentation('');
if (preg_match('#/\* Zend_Code_Generator_FileGenerator-DocBlockMarker \*/#m', $output)) {
$output = preg_replace('#/\* Zend_Code_Generator_FileGenerator-DocBlockMarker \*/#m', $docBlock->generate(), $output, 1);
} else {
$output .= $docBlock->generate() . self::LINE_FEED;
}
}
// newline
$output .= self::LINE_FEED;
// namespace, if any
$namespace = $this->getNamespace();
if ($namespace) {
$namespace = sprintf('namespace %s;%s', $namespace, str_repeat(self::LINE_FEED, 2));
if (preg_match('#/\* Zend_Code_Generator_FileGenerator-NamespaceMarker \*/#m', $output)) {
$output = preg_replace(
'#/\* Zend_Code_Generator_FileGenerator-NamespaceMarker \*/#m',
$namespace,
$output,
1
);
} else {
$output .= $namespace;
}
}
// process required files
// @todo marker replacement for required files
$requiredFiles = $this->getRequiredFiles();
if (!empty($requiredFiles)) {
foreach ($requiredFiles as $requiredFile) {
$output .= 'require_once \'' . $requiredFile . '\';' . self::LINE_FEED;
}
$output .= self::LINE_FEED;
}
$classes = $this->getClasses();
$classUses = array();
//build uses array
foreach ($classes as $class) {
//check for duplicate use statements
$uses = $class->getUses();
if (!empty($uses) && is_array($uses)) {
$classUses = array_merge($classUses, $uses);
}
}
// process import statements
$uses = $this->getUses();
if (!empty($uses)) {
$useOutput = '';
foreach ($uses as $use) {
list($import, $alias) = $use;
if (null === $alias) {
$tempOutput = sprintf('%s', $import);
} else {
$tempOutput = sprintf('%s as %s', $import, $alias);
}
//don't duplicate use statements
if (!in_array($tempOutput, $classUses)) {
$useOutput .= "use ". $tempOutput .";";
$useOutput .= self::LINE_FEED;
}
}
$useOutput .= self::LINE_FEED;
if (preg_match('#/\* Zend_Code_Generator_FileGenerator-UseMarker \*/#m', $output)) {
$output = preg_replace(
'#/\* Zend_Code_Generator_FileGenerator-UseMarker \*/#m',
$useOutput,
$output,
1
);
} else {
$output .= $useOutput;
}
}
// process classes
if (!empty($classes)) {
foreach ($classes as $class) {
$regex = str_replace('&', $class->getName(), '/\* Zend_Code_Generator_Php_File-ClassMarker: \{[A-Za-z0-9\\\]+?&\} \*/');
if (preg_match('#' . $regex . '#m', $output)) {
$output = preg_replace('#' . $regex . '#', $class->generate(), $output, 1);
} else {
if ($namespace) {
$class->setNamespaceName(null);
}
$output .= $class->generate() . self::LINE_FEED;
}
}
}
if (!empty($body)) {
// add an extra space between classes and
if (!empty($classes)) {
$output .= self::LINE_FEED;
}
$output .= $body;
}
return $output;
}
/**
* @return FileGenerator
* @throws Exception\RuntimeException
*/
public function write()
{
if ($this->filename == '' || !is_writable(dirname($this->filename))) {
throw new Exception\RuntimeException('This code generator object is not writable.');
}
file_put_contents($this->filename, $this->generate());
return $this;
}
}

View File

@@ -0,0 +1,44 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator;
use Zend\Code\Generator\Exception\RuntimeException;
class FileGeneratorRegistry
{
/**
* @var array $fileCodeGenerators
*/
private static $fileCodeGenerators = array();
/**
* Registry for the Zend\Code package.
*
* @param FileGenerator $fileCodeGenerator
* @param string $fileName
* @throws RuntimeException
*/
public static function registerFileCodeGenerator(FileGenerator $fileCodeGenerator, $fileName = null)
{
if ($fileName === null) {
$fileName = $fileCodeGenerator->getFilename();
}
if ($fileName == '') {
throw new RuntimeException('FileName does not exist.');
}
// cannot use realpath since the file might not exist, but we do need to have the index
// in the same DIRECTORY_SEPARATOR that realpath would use:
$fileName = str_replace(array('\\', '/'), DIRECTORY_SEPARATOR, $fileName);
static::$fileCodeGenerators[$fileName] = $fileCodeGenerator;
}
}

View File

@@ -0,0 +1,15 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator;
interface GeneratorInterface
{
public function generate();
}

View File

@@ -0,0 +1,313 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator;
use Zend\Code\Reflection\MethodReflection;
class MethodGenerator extends AbstractMemberGenerator
{
/**
* @var DocBlockGenerator
*/
protected $docBlock = null;
/**
* @var ParameterGenerator[]
*/
protected $parameters = array();
/**
* @var string
*/
protected $body = null;
/**
* @param MethodReflection $reflectionMethod
* @return MethodGenerator
*/
public static function fromReflection(MethodReflection $reflectionMethod)
{
$method = new static();
$method->setSourceContent($reflectionMethod->getContents(false));
$method->setSourceDirty(false);
if ($reflectionMethod->getDocComment() != '') {
$method->setDocBlock(DocBlockGenerator::fromReflection($reflectionMethod->getDocBlock()));
}
$method->setFinal($reflectionMethod->isFinal());
if ($reflectionMethod->isPrivate()) {
$method->setVisibility(self::VISIBILITY_PRIVATE);
} elseif ($reflectionMethod->isProtected()) {
$method->setVisibility(self::VISIBILITY_PROTECTED);
} else {
$method->setVisibility(self::VISIBILITY_PUBLIC);
}
$method->setStatic($reflectionMethod->isStatic());
$method->setName($reflectionMethod->getName());
foreach ($reflectionMethod->getParameters() as $reflectionParameter) {
$method->setParameter(ParameterGenerator::fromReflection($reflectionParameter));
}
$method->setBody(static::clearBodyIndention($reflectionMethod->getBody()));
return $method;
}
/**
* Identify the space indention from the first line and remove this indention
* from all lines
*
* @param string $body
*
* @return string
*/
protected static function clearBodyIndention($body)
{
if (empty($body)) {
return $body;
}
$lines = explode(PHP_EOL, $body);
$indention = str_replace(trim($lines[1]), '', $lines[1]);
foreach ($lines as $key => $line) {
if (substr($line, 0, strlen($indention)) == $indention) {
$lines[$key] = substr($line, strlen($indention));
}
}
$body = implode(PHP_EOL, $lines);
return $body;
}
/**
* Generate from array
*
* @configkey name string [required] Class Name
* @configkey docblock string The docblock information
* @configkey flags int Flags, one of MethodGenerator::FLAG_ABSTRACT MethodGenerator::FLAG_FINAL
* @configkey parameters string Class which this class is extending
* @configkey body string
* @configkey abstract bool
* @configkey final bool
* @configkey static bool
* @configkey visibility string
*
* @throws Exception\InvalidArgumentException
* @param array $array
* @return MethodGenerator
*/
public static function fromArray(array $array)
{
if (!isset($array['name'])) {
throw new Exception\InvalidArgumentException(
'Method generator requires that a name is provided for this object'
);
}
$method = new static($array['name']);
foreach ($array as $name => $value) {
// normalize key
switch (strtolower(str_replace(array('.', '-', '_'), '', $name))) {
case 'docblock':
$docBlock = ($value instanceof DocBlockGenerator) ? $value : DocBlockGenerator::fromArray($value);
$method->setDocBlock($docBlock);
break;
case 'flags':
$method->setFlags($value);
break;
case 'parameters':
$method->setParameters($value);
break;
case 'body':
$method->setBody($value);
break;
case 'abstract':
$method->setAbstract($value);
break;
case 'final':
$method->setFinal($value);
break;
case 'static':
$method->setStatic($value);
break;
case 'visibility':
$method->setVisibility($value);
break;
}
}
return $method;
}
/**
* @param string $name
* @param array $parameters
* @param int $flags
* @param string $body
* @param DocBlockGenerator|string $docBlock
*/
public function __construct(
$name = null,
array $parameters = array(),
$flags = self::FLAG_PUBLIC,
$body = null,
$docBlock = null
) {
if ($name) {
$this->setName($name);
}
if ($parameters) {
$this->setParameters($parameters);
}
if ($flags !== self::FLAG_PUBLIC) {
$this->setFlags($flags);
}
if ($body) {
$this->setBody($body);
}
if ($docBlock) {
$this->setDocBlock($docBlock);
}
}
/**
* @param array $parameters
* @return MethodGenerator
*/
public function setParameters(array $parameters)
{
foreach ($parameters as $parameter) {
$this->setParameter($parameter);
}
return $this;
}
/**
* @param ParameterGenerator|array|string $parameter
* @throws Exception\InvalidArgumentException
* @return MethodGenerator
*/
public function setParameter($parameter)
{
if (is_string($parameter)) {
$parameter = new ParameterGenerator($parameter);
}
if (is_array($parameter)) {
$parameter = ParameterGenerator::fromArray($parameter);
}
if (!$parameter instanceof ParameterGenerator) {
throw new Exception\InvalidArgumentException(sprintf(
'%s is expecting either a string, array or an instance of %s\ParameterGenerator',
__METHOD__,
__NAMESPACE__
));
}
$this->parameters[$parameter->getName()] = $parameter;
return $this;
}
/**
* @return ParameterGenerator[]
*/
public function getParameters()
{
return $this->parameters;
}
/**
* @param string $body
* @return MethodGenerator
*/
public function setBody($body)
{
$this->body = $body;
return $this;
}
/**
* @return string
*/
public function getBody()
{
return $this->body;
}
/**
* @return string
*/
public function generate()
{
$output = '';
$indent = $this->getIndentation();
if (($docBlock = $this->getDocBlock()) !== null) {
$docBlock->setIndentation($indent);
$output .= $docBlock->generate();
}
$output .= $indent;
if ($this->isAbstract()) {
$output .= 'abstract ';
} else {
$output .= (($this->isFinal()) ? 'final ' : '');
}
$output .= $this->getVisibility()
. (($this->isStatic()) ? ' static' : '')
. ' function ' . $this->getName() . '(';
$parameters = $this->getParameters();
if (!empty($parameters)) {
foreach ($parameters as $parameter) {
$parameterOutput[] = $parameter->generate();
}
$output .= implode(', ', $parameterOutput);
}
$output .= ')';
if ($this->isAbstract()) {
return $output . ';';
}
$output .= self::LINE_FEED . $indent . '{' . self::LINE_FEED;
if ($this->body) {
$output .= preg_replace('#^((?![a-zA-Z0-9_-]+;).+?)$#m', $indent . $indent . '$1', trim($this->body))
. self::LINE_FEED;
}
$output .= $indent . '}' . self::LINE_FEED;
return $output;
}
public function __toString()
{
return $this->generate();
}
}

View File

@@ -0,0 +1,300 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator;
use Zend\Code\Reflection\ParameterReflection;
class ParameterGenerator extends AbstractGenerator
{
/**
* @var string
*/
protected $name = null;
/**
* @var string
*/
protected $type = null;
/**
* @var string|ValueGenerator
*/
protected $defaultValue = null;
/**
* @var int
*/
protected $position = null;
/**
* @var bool
*/
protected $passedByReference = false;
/**
* @var array
*/
protected static $simple = array('int', 'bool', 'string', 'float', 'resource', 'mixed', 'object');
/**
* @param ParameterReflection $reflectionParameter
* @return ParameterGenerator
*/
public static function fromReflection(ParameterReflection $reflectionParameter)
{
$param = new ParameterGenerator();
$param->setName($reflectionParameter->getName());
if ($reflectionParameter->isArray()) {
$param->setType('array');
} elseif (method_exists($reflectionParameter, 'isCallable') && $reflectionParameter->isCallable()) {
$param->setType('callable');
} else {
$typeClass = $reflectionParameter->getClass();
if ($typeClass) {
$parameterType = $typeClass->getName();
$currentNamespace = $reflectionParameter->getDeclaringClass()->getNamespaceName();
if (!empty($currentNamespace) && substr($parameterType, 0, strlen($currentNamespace)) == $currentNamespace) {
$parameterType = substr($parameterType, strlen($currentNamespace) + 1);
} else {
$parameterType = '\\' . trim($parameterType, '\\');
}
$param->setType($parameterType);
}
}
$param->setPosition($reflectionParameter->getPosition());
if ($reflectionParameter->isOptional()) {
$param->setDefaultValue($reflectionParameter->getDefaultValue());
}
$param->setPassedByReference($reflectionParameter->isPassedByReference());
return $param;
}
/**
* Generate from array
*
* @configkey name string [required] Class Name
* @configkey type string
* @configkey defaultvalue null|bool|string|int|float|array|ValueGenerator
* @configkey passedbyreference bool
* @configkey position int
* @configkey sourcedirty bool
* @configkey indentation string
* @configkey sourcecontent string
*
* @throws Exception\InvalidArgumentException
* @param array $array
* @return ParameterGenerator
*/
public static function fromArray(array $array)
{
if (!isset($array['name'])) {
throw new Exception\InvalidArgumentException(
'Paramerer generator requires that a name is provided for this object'
);
}
$param = new static($array['name']);
foreach ($array as $name => $value) {
// normalize key
switch (strtolower(str_replace(array('.', '-', '_'), '', $name))) {
case 'type':
$param->setType($value);
break;
case 'defaultvalue':
$param->setDefaultValue($value);
break;
case 'passedbyreference':
$param->setPassedByReference($value);
break;
case 'position':
$param->setPosition($value);
break;
case 'sourcedirty':
$param->setSourceDirty($value);
break;
case 'indentation':
$param->setIndentation($value);
break;
case 'sourcecontent':
$param->setSourceContent($value);
break;
}
}
return $param;
}
/**
* @param string $name
* @param string $type
* @param mixed $defaultValue
* @param int $position
* @param bool $passByReference
*/
public function __construct(
$name = null,
$type = null,
$defaultValue = null,
$position = null,
$passByReference = false
) {
if (null !== $name) {
$this->setName($name);
}
if (null !== $type) {
$this->setType($type);
}
if (null !== $defaultValue) {
$this->setDefaultValue($defaultValue);
}
if (null !== $position) {
$this->setPosition($position);
}
if (false !== $passByReference) {
$this->setPassedByReference(true);
}
}
/**
* @param string $type
* @return ParameterGenerator
*/
public function setType($type)
{
$this->type = (string) $type;
return $this;
}
/**
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* @param string $name
* @return ParameterGenerator
*/
public function setName($name)
{
$this->name = (string) $name;
return $this;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Set the default value of the parameter.
*
* Certain variables are difficult to express
*
* @param null|bool|string|int|float|array|ValueGenerator $defaultValue
* @return ParameterGenerator
*/
public function setDefaultValue($defaultValue)
{
if (!($defaultValue instanceof ValueGenerator)) {
$defaultValue = new ValueGenerator($defaultValue);
}
$this->defaultValue = $defaultValue;
return $this;
}
/**
* @return string
*/
public function getDefaultValue()
{
return $this->defaultValue;
}
/**
* @param int $position
* @return ParameterGenerator
*/
public function setPosition($position)
{
$this->position = (int) $position;
return $this;
}
/**
* @return int
*/
public function getPosition()
{
return $this->position;
}
/**
* @return bool
*/
public function getPassedByReference()
{
return $this->passedByReference;
}
/**
* @param bool $passedByReference
* @return ParameterGenerator
*/
public function setPassedByReference($passedByReference)
{
$this->passedByReference = (bool) $passedByReference;
return $this;
}
/**
* @return string
*/
public function generate()
{
$output = '';
if ($this->type && !in_array($this->type, static::$simple)) {
$output .= $this->type . ' ';
}
if (true === $this->passedByReference) {
$output .= '&';
}
$output .= '$' . $this->name;
if ($this->defaultValue !== null) {
$output .= ' = ';
if (is_string($this->defaultValue)) {
$output .= ValueGenerator::escape($this->defaultValue);
} elseif ($this->defaultValue instanceof ValueGenerator) {
$this->defaultValue->setOutputMode(ValueGenerator::OUTPUT_SINGLE_LINE);
$output .= $this->defaultValue;
} else {
$output .= $this->defaultValue;
}
}
return $output;
}
}

View File

@@ -0,0 +1,226 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator;
use Zend\Code\Reflection\PropertyReflection;
class PropertyGenerator extends AbstractMemberGenerator
{
const FLAG_CONSTANT = 0x08;
/**
* @var bool
*/
protected $isConst = null;
/**
* @var PropertyValueGenerator
*/
protected $defaultValue = null;
/**
* @param PropertyReflection $reflectionProperty
* @return PropertyGenerator
*/
public static function fromReflection(PropertyReflection $reflectionProperty)
{
$property = new static();
$property->setName($reflectionProperty->getName());
$allDefaultProperties = $reflectionProperty->getDeclaringClass()->getDefaultProperties();
$property->setDefaultValue($allDefaultProperties[$reflectionProperty->getName()]);
if ($reflectionProperty->getDocComment() != '') {
$property->setDocBlock(DocBlockGenerator::fromReflection($reflectionProperty->getDocBlock()));
}
if ($reflectionProperty->isStatic()) {
$property->setStatic(true);
}
if ($reflectionProperty->isPrivate()) {
$property->setVisibility(self::VISIBILITY_PRIVATE);
} elseif ($reflectionProperty->isProtected()) {
$property->setVisibility(self::VISIBILITY_PROTECTED);
} else {
$property->setVisibility(self::VISIBILITY_PUBLIC);
}
$property->setSourceDirty(false);
return $property;
}
/**
* Generate from array
*
* @configkey name string [required] Class Name
* @configkey const bool
* @configkey defaultvalue null|bool|string|int|float|array|ValueGenerator
* @configkey flags int
* @configkey abstract bool
* @configkey final bool
* @configkey static bool
* @configkey visibility string
*
* @throws Exception\InvalidArgumentException
* @param array $array
* @return PropertyGenerator
*/
public static function fromArray(array $array)
{
if (!isset($array['name'])) {
throw new Exception\InvalidArgumentException(
'Property generator requires that a name is provided for this object'
);
}
$property = new static($array['name']);
foreach ($array as $name => $value) {
// normalize key
switch (strtolower(str_replace(array('.', '-', '_'), '', $name))) {
case 'const':
$property->setConst($value);
break;
case 'defaultvalue':
$property->setDefaultValue($value);
break;
case 'docblock':
$docBlock = ($value instanceof DocBlockGenerator) ? $value : DocBlockGenerator::fromArray($value);
$property->setDocBlock($docBlock);
break;
case 'flags':
$property->setFlags($value);
break;
case 'abstract':
$property->setAbstract($value);
break;
case 'final':
$property->setFinal($value);
break;
case 'static':
$property->setStatic($value);
break;
case 'visibility':
$property->setVisibility($value);
break;
}
}
return $property;
}
/**
* @param string $name
* @param PropertyValueGenerator|string|array $defaultValue
* @param int $flags
*/
public function __construct($name = null, $defaultValue = null, $flags = self::FLAG_PUBLIC)
{
if (null !== $name) {
$this->setName($name);
}
if (null !== $defaultValue) {
$this->setDefaultValue($defaultValue);
}
if ($flags !== self::FLAG_PUBLIC) {
$this->setFlags($flags);
}
}
/**
* @param bool $const
* @return PropertyGenerator
*/
public function setConst($const)
{
if ($const) {
$this->removeFlag(self::FLAG_PUBLIC | self::FLAG_PRIVATE | self::FLAG_PROTECTED);
$this->setFlags(self::FLAG_CONSTANT);
} else {
$this->removeFlag(self::FLAG_CONSTANT);
}
return $this;
}
/**
* @return bool
*/
public function isConst()
{
return (bool) ($this->flags & self::FLAG_CONSTANT);
}
/**
* @param PropertyValueGenerator|mixed $defaultValue
* @param string $defaultValueType
* @param string $defaultValueOutputMode
*
* @return PropertyGenerator
*/
public function setDefaultValue($defaultValue, $defaultValueType = PropertyValueGenerator::TYPE_AUTO, $defaultValueOutputMode = PropertyValueGenerator::OUTPUT_MULTIPLE_LINE)
{
if (!($defaultValue instanceof PropertyValueGenerator)) {
$defaultValue = new PropertyValueGenerator($defaultValue, $defaultValueType, $defaultValueOutputMode);
}
$this->defaultValue = $defaultValue;
return $this;
}
/**
* @return PropertyValueGenerator
*/
public function getDefaultValue()
{
return $this->defaultValue;
}
/**
* @throws Exception\RuntimeException
* @return string
*/
public function generate()
{
$name = $this->getName();
$defaultValue = $this->getDefaultValue();
$output = '';
if (($docBlock = $this->getDocBlock()) !== null) {
$docBlock->setIndentation(' ');
$output .= $docBlock->generate();
}
if ($this->isConst()) {
if ($defaultValue !== null && !$defaultValue->isValidConstantType()) {
throw new Exception\RuntimeException(sprintf(
'The property %s is said to be '
. 'constant but does not have a valid constant value.',
$this->name
));
}
$output .= $this->indentation . 'const ' . $name . ' = '
. (($defaultValue !== null) ? $defaultValue->generate() : 'null;');
} else {
$output .= $this->indentation
. $this->getVisibility()
. (($this->isStatic()) ? ' static' : '')
. ' $' . $name . ' = '
. (($defaultValue !== null) ? $defaultValue->generate() : 'null;');
}
return $output;
}
}

View File

@@ -0,0 +1,23 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator;
class PropertyValueGenerator extends ValueGenerator
{
protected $arrayDepth = 1;
/**
* @return string
*/
public function generate()
{
return parent::generate() . ';';
}
}

View File

@@ -0,0 +1,173 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator;
use Zend\Code\Reflection\ClassReflection;
class TraitGenerator extends ClassGenerator
{
const OBJECT_TYPE = 'trait';
/**
* Build a Code Generation Php Object from a Class Reflection
*
* @param ClassReflection $classReflection
* @return TraitGenerator
*/
public static function fromReflection(ClassReflection $classReflection)
{
// class generator
$cg = new static($classReflection->getName());
$cg->setSourceContent($cg->getSourceContent());
$cg->setSourceDirty(false);
if ($classReflection->getDocComment() != '') {
$cg->setDocBlock(DocBlockGenerator::fromReflection($classReflection->getDocBlock()));
}
// set the namespace
if ($classReflection->inNamespace()) {
$cg->setNamespaceName($classReflection->getNamespaceName());
}
$properties = array();
foreach ($classReflection->getProperties() as $reflectionProperty) {
if ($reflectionProperty->getDeclaringClass()->getName() == $classReflection->getName()) {
$properties[] = PropertyGenerator::fromReflection($reflectionProperty);
}
}
$cg->addProperties($properties);
$methods = array();
foreach ($classReflection->getMethods() as $reflectionMethod) {
$className = ($cg->getNamespaceName())
? $cg->getNamespaceName() . '\\' . $cg->getName()
: $cg->getName();
if ($reflectionMethod->getDeclaringClass()->getName() == $className) {
$methods[] = MethodGenerator::fromReflection($reflectionMethod);
}
}
$cg->addMethods($methods);
return $cg;
}
/**
* Generate from array
*
* @configkey name string [required] Class Name
* @configkey filegenerator FileGenerator File generator that holds this class
* @configkey namespacename string The namespace for this class
* @configkey docblock string The docblock information
* @configkey properties
* @configkey methods
*
* @throws Exception\InvalidArgumentException
* @param array $array
* @return TraitGenerator
*/
public static function fromArray(array $array)
{
if (! isset($array['name'])) {
throw new Exception\InvalidArgumentException(
'Class generator requires that a name is provided for this object'
);
}
$cg = new static($array['name']);
foreach ($array as $name => $value) {
// normalize key
switch (strtolower(str_replace(array('.', '-', '_'), '', $name))) {
case 'containingfile':
$cg->setContainingFileGenerator($value);
break;
case 'namespacename':
$cg->setNamespaceName($value);
break;
case 'docblock':
$docBlock = ($value instanceof DocBlockGenerator) ? $value : DocBlockGenerator::fromArray($value);
$cg->setDocBlock($docBlock);
break;
case 'properties':
$cg->addProperties($value);
break;
case 'methods':
$cg->addMethods($value);
break;
}
}
return $cg;
}
/**
* @param array|string $flags
* @return self
*/
public function setFlags($flags)
{
return $this;
}
/**
* @param string $flag
* @return self
*/
public function addFlag($flag)
{
return $this;
}
/**
* @param string $flag
* @return self
*/
public function removeFlag($flag)
{
return $this;
}
/**
* @param bool $isFinal
* @return self
*/
public function setFinal($isFinal)
{
return $this;
}
/**
* @param string $extendedClass
* @return self
*/
public function setExtendedClass($extendedClass)
{
return $this;
}
/**
* @param array $implementedInterfaces
* @return self
*/
public function setImplementedInterfaces(array $implementedInterfaces)
{
return $this;
}
/**
* @param bool $isAbstract
* @return self
*/
public function setAbstract($isAbstract)
{
return $this;
}
}

View File

@@ -0,0 +1,353 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator;
use Reflection;
use ReflectionMethod;
class TraitUsageGenerator extends AbstractGenerator
{
/**
* @var ClassGenerator
*/
protected $classGenerator;
/**
* @var array Array of trait names
*/
protected $traits = array();
/**
* @var array Array of trait aliases
*/
protected $traitAliases = array();
/**
* @var array Array of trait overrides
*/
protected $traitOverrides = array();
/**
* @var array Array of string names
*/
protected $uses = array();
public function __construct(ClassGenerator $classGenerator)
{
$this->classGenerator = $classGenerator;
}
/**
* @inherit Zend\Code\Generator\TraitUsageInterface
*/
public function addUse($use, $useAlias = null)
{
if (! empty($useAlias)) {
$use .= ' as ' . $useAlias;
}
$this->uses[$use] = $use;
return $this;
}
/**
* @inherit Zend\Code\Generator\TraitUsageInterface
*/
public function getUses()
{
return array_values($this->uses);
}
/**
* @inherit Zend\Code\Generator\TraitUsageInterface
*/
public function addTrait($trait)
{
$traitName = $trait;
if (is_array($trait)) {
if (! array_key_exists('traitName', $trait)) {
throw new Exception\InvalidArgumentException('Missing required value for traitName');
}
$traitName = $trait['traitName'];
if (array_key_exists('aliases', $trait)) {
foreach ($trait['aliases'] as $alias) {
$this->addAlias($alias);
}
}
if (array_key_exists('insteadof', $trait)) {
foreach ($trait['insteadof'] as $insteadof) {
$this->addTraitOverride($insteadof);
}
}
}
if (! $this->hasTrait($traitName)) {
$this->traits[] = $traitName;
}
return $this;
}
/**
* @inherit Zend\Code\Generator\TraitUsageInterface
*/
public function addTraits(array $traits)
{
foreach ($traits as $trait) {
$this->addTrait($trait);
}
return $this;
}
/**
* @inherit Zend\Code\Generator\TraitUsageInterface
*/
public function hasTrait($traitName)
{
return in_array($traitName, $this->traits);
}
/**
* @inherit Zend\Code\Generator\TraitUsageInterface
*/
public function getTraits()
{
return $this->traits;
}
/**
* @inherit Zend\Code\Generator\TraitUsageInterface
*/
public function removeTrait($traitName)
{
$key = array_search($traitName, $this->traits);
if (false !== $key) {
unset($this->traits[$key]);
}
return $this;
}
/**
* @inherit Zend\Code\Generator\TraitUsageInterface
*/
public function addTraitAlias($method, $alias, $visibility = null)
{
$traitAndMethod = $method;
if (is_array($method)) {
if (! array_key_exists('traitName', $method)) {
throw new Exception\InvalidArgumentException('Missing required argument "traitName" for $method');
}
if (! array_key_exists('method', $method)) {
throw new Exception\InvalidArgumentException('Missing required argument "method" for $method');
}
$traitAndMethod = $method['traitName'] . '::' . $method['method'];
}
// Validations
if (false === strpos($traitAndMethod, "::")) {
throw new Exception\InvalidArgumentException(
'Invalid Format: $method must be in the format of trait::method'
);
}
if (! is_string($alias)) {
throw new Exception\InvalidArgumentException('Invalid Alias: $alias must be a string or array.');
}
if ($this->classGenerator->hasMethod($alias)) {
throw new Exception\InvalidArgumentException('Invalid Alias: Method name already exists on this class.');
}
if (null !== $visibility
&& $visibility !== ReflectionMethod::IS_PUBLIC
&& $visibility !== ReflectionMethod::IS_PRIVATE
&& $visibility !== ReflectionMethod::IS_PROTECTED
) {
throw new Exception\InvalidArgumentException(
'Invalid Type: $visibility must of ReflectionMethod::IS_PUBLIC,'
. ' ReflectionMethod::IS_PRIVATE or ReflectionMethod::IS_PROTECTED'
);
}
list($trait, $method) = explode('::', $traitAndMethod);
if (! $this->hasTrait($trait)) {
throw new Exception\InvalidArgumentException('Invalid trait: Trait does not exists on this class');
}
$this->traitAliases[$traitAndMethod] = array(
'alias' => $alias,
'visibility' => $visibility
);
return $this;
}
/**
* @inherit Zend\Code\Generator\TraitUsageInterface
*/
public function getTraitAliases()
{
return $this->traitAliases;
}
/**
* @inherit Zend\Code\Generator\TraitUsageInterface
*/
public function addTraitOverride($method, $traitsToReplace)
{
if (false === is_array($traitsToReplace)) {
$traitsToReplace = array($traitsToReplace);
}
$traitAndMethod = $method;
if (is_array($method)) {
if (! array_key_exists('traitName', $method)) {
throw new Exception\InvalidArgumentException('Missing required argument "traitName" for $method');
}
if (! array_key_exists('method', $method)) {
throw new Exception\InvalidArgumentException('Missing required argument "method" for $method');
}
$traitAndMethod = (string) $method['traitName'] . '::' . (string) $method['method'];
}
// Validations
if (false === strpos($traitAndMethod, "::")) {
throw new Exception\InvalidArgumentException(
'Invalid Format: $method must be in the format of trait::method'
);
}
list($trait, $method) = explode("::", $traitAndMethod);
if (! $this->hasTrait($trait)) {
throw new Exception\InvalidArgumentException('Invalid trait: Trait does not exists on this class');
}
if (! array_key_exists($traitAndMethod, $this->traitOverrides)) {
$this->traitOverrides[$traitAndMethod] = array();
}
foreach ($traitsToReplace as $traitToReplace) {
if (! is_string($traitToReplace)) {
throw new Exception\InvalidArgumentException(
'Invalid Argument: $traitToReplace must be a string or array of strings'
);
}
if (! in_array($traitToReplace, $this->traitOverrides[$traitAndMethod])) {
$this->traitOverrides[$traitAndMethod][] = $traitToReplace;
}
}
return $this;
}
/**
* @inherit Zend\Code\Generator\TraitUsageInterface
*/
public function removeTraitOverride($method, $overridesToRemove = null)
{
if (! array_key_exists($method, $this->traitOverrides)) {
return $this;
}
if (null === $overridesToRemove) {
unset($this->traitOverrides[$method]);
return $this;
}
$overridesToRemove = (! is_array($overridesToRemove))
? array($overridesToRemove)
: $overridesToRemove;
foreach ($overridesToRemove as $traitToRemove) {
$key = array_search($traitToRemove, $this->traitOverrides[$method]);
if (false !== $key) {
unset($this->traitOverrides[$method][$key]);
}
}
return $this;
}
/**
* @inherit Zend\Code\Generator\TraitUsageInterface
*/
public function getTraitOverrides()
{
return $this->traitOverrides;
}
/**
* @inherit Zend\Code\Generator\GeneratorInterface
*/
public function generate()
{
$output = '';
$indent = $this->getIndentation();
$traits = $this->getTraits();
if (empty($traits)) {
return $output;
}
$output .= $indent . 'use ' . implode(', ', $traits);
$aliases = $this->getTraitAliases();
$overrides = $this->getTraitOverrides();
if (empty($aliases) && empty($overrides)) {
$output .= ";" . self::LINE_FEED . self::LINE_FEED;
return $output;
}
$output .= ' {' . self::LINE_FEED;
foreach ($aliases as $method => $alias) {
$visibility = (null !== $alias['visibility'])
? current(Reflection::getModifierNames($alias['visibility'])) . ' '
: '';
// validation check
if ($this->classGenerator->hasMethod($alias['alias'])) {
throw new Exception\RuntimeException(sprintf(
'Generation Error: Aliased method %s already exists on this class',
$alias['alias']
));
}
$output .=
$indent
. $indent
. $method
. ' as '
. $visibility
. $alias['alias']
. ';'
. self::LINE_FEED;
}
foreach ($overrides as $method => $insteadofTraits) {
foreach ($insteadofTraits as $insteadofTrait) {
$output .=
$indent
. $indent
. $method
. ' insteadof '
. $insteadofTrait
. ';'
. self::LINE_FEED;
}
}
$output .= self::LINE_FEED . $indent . '}' . self::LINE_FEED . self::LINE_FEED;
return $output;
}
}

View File

@@ -0,0 +1,159 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator;
interface TraitUsageInterface
{
/**
* Add a class to "use" classes
*
* @param string $use
* @param string|null $useAlias
* @return self
*/
public function addUse($use, $useAlias = null);
/**
* Returns the "use" classes
*
* @return array
*/
public function getUses();
/**
* Add trait takes an array of trait options or string as arguments.
*
* Array Format:
* key: traitName value: String
*
* key: aliases value: array of arrays
* key: method value: @see addTraitAlias
* key: alias value: @see addTraitAlias
* key: visibility value: @see addTraitAlias
*
* key: insteadof value: array of arrays
* key: method value: @see self::addTraitOverride
* key: traitToReplace value: @see self::addTraitOverride
*
* @param mixed $trait String | Array
* @return self
*/
public function addTrait($trait);
/**
* Add multiple traits. Trait can be an array of trait names or array of trait
* configurations
*
* @param array $traitName Array of string names or configurations (@see addTrait)
* @return self
*/
public function addTraits(array $traits);
/**
* Check to see if the class has a trait defined
*
* @param strint $traitName
* @return bool
*/
public function hasTrait($traitName);
/**
* Get a list of trait names
*
* @return array
*/
public function getTraits();
/**
* Remove a trait by its name
*
* @param $traitName
*/
public function removeTrait($traitName);
/**
* Add a trait alias. This will be used to generate the AS portion of the use statement.
*
* $method:
* This method provides 2 ways for defining the trait method.
* Option 1: String
* Option 2: Array
* key: traitName value: name of trait
* key: method value: trait method
*
* $alias:
* Alias is a string representing the new method name.
*
* $visibilty:
* ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PRIVATE| ReflectionMethod::IS_PROTECTED
*
* @param mixed $method String or Array
* @param string $alias
* @param int $visiblity
*/
public function addTraitAlias($method, $alias, $visibility = null);
/**
* @return array
*/
public function getTraitAliases();
/**
* Add a trait method override. This will be used to generate the INSTEADOF portion of the use
* statement.
*
* $method:
* This method provides 2 ways for defining the trait method.
* Option 1: String Format: <trait name>::<method name>
* Option 2: Array
* key: traitName value: trait name
* key: method value: method name
*
* $traitToReplace:
* The name of the trait that you wish to supersede.
*
* This method provides 2 ways for defining the trait method.
* Option 1: String of trait to replace
* Option 2: Array of strings of traits to replace
* @param mixed $method
* @param mixed $traitToReplace
*/
public function addTraitOverride($method, $traitsToReplace);
/**
* Remove an override for a given trait::method
*
* $method:
* This method provides 2 ways for defining the trait method.
* Option 1: String Format: <trait name>::<method name>
* Option 2: Array
* key: traitName value: trait name
* key: method value: method name
*
* $overridesToRemove:
* The name of the trait that you wish to remove.
*
* This method provides 2 ways for defining the trait method.
* Option 1: String of trait to replace
* Option 2: Array of strings of traits to replace
*
* @param $traitAndMethod
* @param null $overridesToRemove
* @return $this
*/
public function removeTraitOverride($method, $overridesToRemove = null);
/**
* Return trait overrides
*
* @return array
*/
public function getTraitOverrides();
}

View File

@@ -0,0 +1,435 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generator;
use Zend\Stdlib\ArrayObject;
class ValueGenerator extends AbstractGenerator
{
/**#@+
* Constant values
*/
const TYPE_AUTO = 'auto';
const TYPE_BOOLEAN = 'boolean';
const TYPE_BOOL = 'bool';
const TYPE_NUMBER = 'number';
const TYPE_INTEGER = 'integer';
const TYPE_INT = 'int';
const TYPE_FLOAT = 'float';
const TYPE_DOUBLE = 'double';
const TYPE_STRING = 'string';
const TYPE_ARRAY = 'array';
const TYPE_CONSTANT = 'constant';
const TYPE_NULL = 'null';
const TYPE_OBJECT = 'object';
const TYPE_OTHER = 'other';
/**#@-*/
const OUTPUT_MULTIPLE_LINE = 'multipleLine';
const OUTPUT_SINGLE_LINE = 'singleLine';
/**
* @var mixed
*/
protected $value = null;
/**
* @var string
*/
protected $type = self::TYPE_AUTO;
/**
* @var int
*/
protected $arrayDepth = 0;
/**
* @var string
*/
protected $outputMode = self::OUTPUT_MULTIPLE_LINE;
/**
* @var array
*/
protected $allowedTypes = null;
/**
* Autodetectable constants
* @var ArrayObject
*/
protected $constants = null;
/**
* @param mixed $value
* @param string $type
* @param string $outputMode
* @param ArrayObject $constants
*/
public function __construct($value = null, $type = self::TYPE_AUTO, $outputMode = self::OUTPUT_MULTIPLE_LINE, ArrayObject $constants = null)
{
// strict check is important here if $type = AUTO
if ($value !== null) {
$this->setValue($value);
}
if ($type !== self::TYPE_AUTO) {
$this->setType($type);
}
if ($outputMode !== self::OUTPUT_MULTIPLE_LINE) {
$this->setOutputMode($outputMode);
}
if ($constants !== null) {
$this->constants = $constants;
} else {
$this->constants = new ArrayObject();
}
}
/**
* Init constant list by defined and magic constants
*/
public function initEnvironmentConstants()
{
$constants = array(
'__DIR__',
'__FILE__',
'__LINE__',
'__CLASS__',
'__TRAIT__',
'__METHOD__',
'__FUNCTION__',
'__NAMESPACE__',
'::'
);
$constants = array_merge($constants, array_keys(get_defined_constants()), $this->constants->getArrayCopy());
$this->constants->exchangeArray($constants);
}
/**
* Add constant to list
*
* @param string $constant
*
* @return $this
*/
public function addConstant($constant)
{
$this->constants->append($constant);
return $this;
}
/**
* Delete constant from constant list
*
* @param string $constant
*
* @return bool
*/
public function deleteConstant($constant)
{
if (($index = array_search($constant, $this->constants->getArrayCopy())) !== false) {
$this->constants->offsetUnset($index);
}
return $index !== false;
}
/**
* Return constant list
*
* @return ArrayObject
*/
public function getConstants()
{
return $this->constants;
}
/**
* @return bool
*/
public function isValidConstantType()
{
if ($this->type == self::TYPE_AUTO) {
$type = $this->getAutoDeterminedType($this->value);
} else {
$type = $this->type;
}
// valid types for constants
$scalarTypes = array(
self::TYPE_BOOLEAN,
self::TYPE_BOOL,
self::TYPE_NUMBER,
self::TYPE_INTEGER,
self::TYPE_INT,
self::TYPE_FLOAT,
self::TYPE_DOUBLE,
self::TYPE_STRING,
self::TYPE_CONSTANT,
self::TYPE_NULL
);
return in_array($type, $scalarTypes);
}
/**
* @param mixed $value
* @return ValueGenerator
*/
public function setValue($value)
{
$this->value = $value;
return $this;
}
/**
* @return mixed
*/
public function getValue()
{
return $this->value;
}
/**
* @param string $type
* @return ValueGenerator
*/
public function setType($type)
{
$this->type = (string) $type;
return $this;
}
/**
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* @param int $arrayDepth
* @return ValueGenerator
*/
public function setArrayDepth($arrayDepth)
{
$this->arrayDepth = (int) $arrayDepth;
return $this;
}
/**
* @return int
*/
public function getArrayDepth()
{
return $this->arrayDepth;
}
/**
* @param string $type
* @return string
*/
protected function getValidatedType($type)
{
$types = array(
self::TYPE_AUTO,
self::TYPE_BOOLEAN,
self::TYPE_BOOL,
self::TYPE_NUMBER,
self::TYPE_INTEGER,
self::TYPE_INT,
self::TYPE_FLOAT,
self::TYPE_DOUBLE,
self::TYPE_STRING,
self::TYPE_ARRAY,
self::TYPE_CONSTANT,
self::TYPE_NULL,
self::TYPE_OBJECT,
self::TYPE_OTHER
);
if (in_array($type, $types)) {
return $type;
}
return self::TYPE_AUTO;
}
/**
* @param mixed $value
* @return string
*/
public function getAutoDeterminedType($value)
{
switch (gettype($value)) {
case 'boolean':
return self::TYPE_BOOLEAN;
case 'string':
foreach ($this->constants as $constant) {
if (strpos($value, $constant) !== false) {
return self::TYPE_CONSTANT;
}
}
return self::TYPE_STRING;
case 'double':
case 'float':
case 'integer':
return self::TYPE_NUMBER;
case 'array':
return self::TYPE_ARRAY;
case 'NULL':
return self::TYPE_NULL;
case 'object':
case 'resource':
case 'unknown type':
default:
return self::TYPE_OTHER;
}
}
/**
* @throws Exception\RuntimeException
* @return string
*/
public function generate()
{
$type = $this->type;
if ($type != self::TYPE_AUTO) {
$type = $this->getValidatedType($type);
}
$value = $this->value;
if ($type == self::TYPE_AUTO) {
$type = $this->getAutoDeterminedType($value);
}
if ($type == self::TYPE_ARRAY) {
foreach ($value as &$curValue) {
if ($curValue instanceof self) {
continue;
}
$curValue = new self($curValue, self::TYPE_AUTO, self::OUTPUT_MULTIPLE_LINE, $this->getConstants());
}
}
$output = '';
switch ($type) {
case self::TYPE_BOOLEAN:
case self::TYPE_BOOL:
$output .= ($value ? 'true' : 'false');
break;
case self::TYPE_STRING:
$output .= self::escape($value);
break;
case self::TYPE_NULL:
$output .= 'null';
break;
case self::TYPE_NUMBER:
case self::TYPE_INTEGER:
case self::TYPE_INT:
case self::TYPE_FLOAT:
case self::TYPE_DOUBLE:
case self::TYPE_CONSTANT:
$output .= $value;
break;
case self::TYPE_ARRAY:
$output .= 'array(';
if ($this->outputMode == self::OUTPUT_MULTIPLE_LINE) {
$output .= self::LINE_FEED . str_repeat($this->indentation, $this->arrayDepth + 1);
}
$outputParts = array();
$noKeyIndex = 0;
foreach ($value as $n => $v) {
/* @var $v ValueGenerator */
$v->setArrayDepth($this->arrayDepth + 1);
$partV = $v->generate();
$short = false;
if (is_int($n)) {
if ($n === $noKeyIndex) {
$short = true;
$noKeyIndex++;
} else {
$noKeyIndex = max($n + 1, $noKeyIndex);
}
}
if ($short) {
$outputParts[] = $partV;
} else {
$outputParts[] = (is_int($n) ? $n : self::escape($n)) . ' => ' . $partV;
}
}
$padding = ($this->outputMode == self::OUTPUT_MULTIPLE_LINE)
? self::LINE_FEED . str_repeat($this->indentation, $this->arrayDepth + 1)
: ' ';
$output .= implode(',' . $padding, $outputParts);
if ($this->outputMode == self::OUTPUT_MULTIPLE_LINE) {
if (count($outputParts) > 0) {
$output .= ',';
}
$output .= self::LINE_FEED . str_repeat($this->indentation, $this->arrayDepth);
}
$output .= ')';
break;
case self::TYPE_OTHER:
default:
throw new Exception\RuntimeException(
sprintf('Type "%s" is unknown or cannot be used as property default value.', get_class($value))
);
}
return $output;
}
/**
* Quotes value for PHP code.
*
* @param string $input Raw string.
* @param bool $quote Whether add surrounding quotes or not.
* @return string PHP-ready code.
*/
public static function escape($input, $quote = true)
{
$output = addcslashes($input, "\\'");
// adds quoting strings
if ($quote) {
$output = "'" . $output . "'";
}
return $output;
}
/**
* @param string $outputMode
* @return ValueGenerator
*/
public function setOutputMode($outputMode)
{
$this->outputMode = (string) $outputMode;
return $this;
}
/**
* @return string
*/
public function getOutputMode()
{
return $this->outputMode;
}
public function __toString()
{
return $this->generate();
}
}

View File

@@ -0,0 +1,121 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generic\Prototype;
use Zend\Code\Reflection\Exception;
/**
* This is a factory for classes which are identified by name.
*
* All classes that this factory can supply need to
* be registered before (prototypes). This prototypes need to implement
* an interface which ensures every prototype has a name.
*
* If the factory can not supply the class someone is asking for
* it tries to fallback on a generic default prototype, which would
* have need to be set before.
*/
class PrototypeClassFactory
{
/**
* @var array
*/
protected $prototypes = array();
/**
* @var PrototypeGenericInterface
*/
protected $genericPrototype = null;
/**
* @param PrototypeInterface[] $prototypes
* @param PrototypeGenericInterface $genericPrototype
*/
public function __construct($prototypes = array(), PrototypeGenericInterface $genericPrototype = null)
{
foreach ((array)$prototypes as $prototype) {
$this->addPrototype($prototype);
}
if ($genericPrototype) {
$this->setGenericPrototype($genericPrototype);
}
}
/**
* @param PrototypeInterface $prototype
* @throws Exception\InvalidArgumentException
*/
public function addPrototype(PrototypeInterface $prototype)
{
$prototypeName = $this->normalizeName($prototype->getName());
if (isset($this->prototypes[$prototypeName])) {
throw new Exception\InvalidArgumentException('A prototype with this name already exists in this manager');
}
$this->prototypes[$prototypeName] = $prototype;
}
/**
* @param PrototypeGenericInterface $prototype
* @throws Exception\InvalidArgumentException
*/
public function setGenericPrototype(PrototypeGenericInterface $prototype)
{
if (isset($this->genericPrototype)) {
throw new Exception\InvalidArgumentException('A default prototype is already set');
}
$this->genericPrototype = $prototype;
}
/**
* @param string $name
* @return string
*/
protected function normalizeName($name)
{
return str_replace(array('-', '_'), '', $name);
}
/**
* @param string $name
* @return bool
*/
public function hasPrototype($name)
{
$name = $this->normalizeName($name);
return isset($this->prototypes[$name]);
}
/**
* @param string $prototypeName
* @return PrototypeInterface
* @throws Exception\RuntimeException
*/
public function getClonedPrototype($prototypeName)
{
$prototypeName = $this->normalizeName($prototypeName);
if (!$this->hasPrototype($prototypeName) && !isset($this->genericPrototype)) {
throw new Exception\RuntimeException('This tag name is not supported by this tag manager');
}
if (!$this->hasPrototype($prototypeName)) {
$newPrototype = clone $this->genericPrototype;
$newPrototype->setName($prototypeName);
} else {
$newPrototype = clone $this->prototypes[$prototypeName];
}
return $newPrototype;
}
}

View File

@@ -0,0 +1,18 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generic\Prototype;
interface PrototypeGenericInterface extends PrototypeInterface
{
/**
* @param string $name
*/
public function setName($name);
}

View File

@@ -0,0 +1,18 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Generic\Prototype;
interface PrototypeInterface
{
/**
* @return string
*/
public function getName();
}

View File

@@ -0,0 +1,156 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code;
class NameInformation
{
/**
* @var string
*/
protected $namespace = null;
/**
* @var array
*/
protected $uses = array();
/**
* @param string $namespace
* @param array $uses
*/
public function __construct($namespace = null, array $uses = array())
{
if ($namespace) {
$this->setNamespace($namespace);
}
if ($uses) {
$this->setUses($uses);
}
}
/**
* @param string $namespace
* @return NameInformation
*/
public function setNamespace($namespace)
{
$this->namespace = (string) $namespace;
return $this;
}
/**
* @return string
*/
public function getNamespace()
{
return $this->namespace;
}
/**
* @return bool
*/
public function hasNamespace()
{
return ($this->namespace !== null);
}
/**
* @param array $uses
* @return NameInformation
*/
public function setUses(array $uses)
{
$this->uses = array();
$this->addUses($uses);
return $this;
}
/**
* @param array $uses
* @return NameInformation
*/
public function addUses(array $uses)
{
foreach ($uses as $use => $as) {
if (is_int($use)) {
$this->addUse($as);
} elseif (is_string($use)) {
$this->addUse($use, $as);
}
}
return $this;
}
/**
* @param array|string $use
* @param string $as
*/
public function addUse($use, $as = null)
{
if (is_array($use) && array_key_exists('use', $use) && array_key_exists('as', $use)) {
$uses = $use;
$use = $uses['use'];
$as = $uses['as'];
}
$use = trim($use, '\\');
if ($as === null) {
$as = trim($use, '\\');
$nsSeparatorPosition = strrpos($as, '\\');
if ($nsSeparatorPosition !== false && $nsSeparatorPosition !== 0 && $nsSeparatorPosition != strlen($as)) {
$as = substr($as, $nsSeparatorPosition + 1);
}
}
$this->uses[$use] = $as;
}
/**
* @return array
*/
public function getUses()
{
return $this->uses;
}
/**
* @param string $name
* @return string
*/
public function resolveName($name)
{
if ($this->namespace && !$this->uses && strlen($name) > 0 && $name{0} != '\\') {
return $this->namespace . '\\' . $name;
}
if (!$this->uses || strlen($name) <= 0 || $name{0} == '\\') {
return ltrim($name, '\\');
}
if ($this->namespace || $this->uses) {
$firstPart = $name;
if (($firstPartEnd = strpos($firstPart, '\\')) !== false) {
$firstPart = substr($firstPart, 0, $firstPartEnd);
} else {
$firstPartEnd = strlen($firstPart);
}
if (($fqns = array_search($firstPart, $this->uses)) !== false) {
return substr_replace($name, $fqns, 0, $firstPartEnd);
}
if ($this->namespace) {
return $this->namespace . '\\' . $name;
}
}
return $name;
}
}

View File

@@ -0,0 +1,283 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Reflection;
use ReflectionClass;
use Zend\Code\Annotation\AnnotationCollection;
use Zend\Code\Annotation\AnnotationManager;
use Zend\Code\Scanner\AnnotationScanner;
use Zend\Code\Scanner\FileScanner;
class ClassReflection extends ReflectionClass implements ReflectionInterface
{
/**
* @var AnnotationScanner
*/
protected $annotations = null;
/**
* @var DocBlockReflection
*/
protected $docBlock = null;
/**
* Return the reflection file of the declaring file.
*
* @return FileReflection
*/
public function getDeclaringFile()
{
$instance = new FileReflection($this->getFileName());
return $instance;
}
/**
* Return the classes DocBlock reflection object
*
* @return DocBlockReflection
* @throws Exception\ExceptionInterface for missing DocBock or invalid reflection class
*/
public function getDocBlock()
{
if (isset($this->docBlock)) {
return $this->docBlock;
}
if ('' == $this->getDocComment()) {
return false;
}
$this->docBlock = new DocBlockReflection($this);
return $this->docBlock;
}
/**
* @param AnnotationManager $annotationManager
* @return AnnotationCollection
*/
public function getAnnotations(AnnotationManager $annotationManager)
{
$docComment = $this->getDocComment();
if ($docComment == '') {
return false;
}
if ($this->annotations) {
return $this->annotations;
}
$fileScanner = $this->createFileScanner($this->getFileName());
$nameInformation = $fileScanner->getClassNameInformation($this->getName());
if (!$nameInformation) {
return false;
}
$this->annotations = new AnnotationScanner($annotationManager, $docComment, $nameInformation);
return $this->annotations;
}
/**
* Return the start line of the class
*
* @param bool $includeDocComment
* @return int
*/
public function getStartLine($includeDocComment = false)
{
if ($includeDocComment && $this->getDocComment() != '') {
return $this->getDocBlock()->getStartLine();
}
return parent::getStartLine();
}
/**
* Return the contents of the class
*
* @param bool $includeDocBlock
* @return string
*/
public function getContents($includeDocBlock = true)
{
$fileName = $this->getFileName();
if (false === $fileName || ! file_exists($fileName)) {
return '';
}
$filelines = file($fileName);
$startnum = $this->getStartLine($includeDocBlock);
$endnum = $this->getEndLine() - $this->getStartLine();
// Ensure we get between the open and close braces
$lines = array_slice($filelines, $startnum, $endnum);
array_unshift($lines, $filelines[$startnum-1]);
return strstr(implode('', $lines), '{');
}
/**
* Get all reflection objects of implemented interfaces
*
* @return ClassReflection[]
*/
public function getInterfaces()
{
$phpReflections = parent::getInterfaces();
$zendReflections = array();
while ($phpReflections && ($phpReflection = array_shift($phpReflections))) {
$instance = new ClassReflection($phpReflection->getName());
$zendReflections[] = $instance;
unset($phpReflection);
}
unset($phpReflections);
return $zendReflections;
}
/**
* Return method reflection by name
*
* @param string $name
* @return MethodReflection
*/
public function getMethod($name)
{
$method = new MethodReflection($this->getName(), parent::getMethod($name)->getName());
return $method;
}
/**
* Get reflection objects of all methods
*
* @param int $filter
* @return MethodReflection[]
*/
public function getMethods($filter = -1)
{
$methods = array();
foreach (parent::getMethods($filter) as $method) {
$instance = new MethodReflection($this->getName(), $method->getName());
$methods[] = $instance;
}
return $methods;
}
/**
* Returns an array of reflection classes of traits used by this class.
*
* @return array|null
*/
public function getTraits()
{
$vals = array();
$traits = parent::getTraits();
if ($traits === null) {
return;
}
foreach ($traits as $trait) {
$vals[] = new ClassReflection($trait->getName());
}
return $vals;
}
/**
* Get parent reflection class of reflected class
*
* @return ClassReflection|bool
*/
public function getParentClass()
{
$phpReflection = parent::getParentClass();
if ($phpReflection) {
$zendReflection = new ClassReflection($phpReflection->getName());
unset($phpReflection);
return $zendReflection;
}
return false;
}
/**
* Return reflection property of this class by name
*
* @param string $name
* @return PropertyReflection
*/
public function getProperty($name)
{
$phpReflection = parent::getProperty($name);
$zendReflection = new PropertyReflection($this->getName(), $phpReflection->getName());
unset($phpReflection);
return $zendReflection;
}
/**
* Return reflection properties of this class
*
* @param int $filter
* @return PropertyReflection[]
*/
public function getProperties($filter = -1)
{
$phpReflections = parent::getProperties($filter);
$zendReflections = array();
while ($phpReflections && ($phpReflection = array_shift($phpReflections))) {
$instance = new PropertyReflection($this->getName(), $phpReflection->getName());
$zendReflections[] = $instance;
unset($phpReflection);
}
unset($phpReflections);
return $zendReflections;
}
/**
* @return string
*/
public function toString()
{
return parent::__toString();
}
/**
* @return string
*/
public function __toString()
{
return parent::__toString();
}
/**
* Creates a new FileScanner instance.
*
* By having this as a seperate method it allows the method to be overridden
* if a different FileScanner is needed.
*
* @param string $filename
*
* @return FileScanner
*/
protected function createFileScanner($filename)
{
return new FileScanner($filename);
}
}

View File

@@ -0,0 +1,74 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Reflection\DocBlock\Tag;
class AuthorTag implements TagInterface
{
/**
* @var string
*/
protected $authorName = null;
/**
* @var string
*/
protected $authorEmail = null;
/**
* @return string
*/
public function getName()
{
return 'author';
}
/**
* Initializer
*
* @param string $tagDocblockLine
*/
public function initialize($tagDocblockLine)
{
$match = array();
if (!preg_match('/^([^\<]*)(\<([^\>]*)\>)?(.*)$/u', $tagDocblockLine, $match)) {
return;
}
if ($match[1] !== '') {
$this->authorName = rtrim($match[1]);
}
if (isset($match[3]) && $match[3] !== '') {
$this->authorEmail = $match[3];
}
}
/**
* @return null|string
*/
public function getAuthorName()
{
return $this->authorName;
}
/**
* @return null|string
*/
public function getAuthorEmail()
{
return $this->authorEmail;
}
public function __toString()
{
return 'DocBlock Tag [ * @' . $this->getName() . ' ]' . PHP_EOL;
}
}

View File

@@ -0,0 +1,109 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Reflection\DocBlock\Tag;
use Zend\Code\Generic\Prototype\PrototypeGenericInterface;
class GenericTag implements TagInterface, PrototypeGenericInterface
{
/**
* @var string
*/
protected $name = null;
/**
* @var string
*/
protected $content = null;
/**
* @var null|string
*/
protected $contentSplitCharacter = null;
/**
* @var array
*/
protected $values = array();
/**
* @param string $contentSplitCharacter
*/
public function __construct($contentSplitCharacter = ' ')
{
$this->contentSplitCharacter = $contentSplitCharacter;
}
/**
* @param string $tagDocBlockLine
* @return void
*/
public function initialize($tagDocBlockLine)
{
$this->parse($tagDocBlockLine);
}
/**
* Get annotation tag name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @param string $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* @return string
*/
public function getContent()
{
return $this->content;
}
/**
* @param int $position
* @return string
*/
public function returnValue($position)
{
return $this->values[$position];
}
/**
* Serialize to string
*
* Required by Reflector
*
* @todo What should this do?
* @return string
*/
public function __toString()
{
return 'DocBlock Tag [ * @' . $this->name . ' ]' . PHP_EOL;
}
/**
* @param string $docBlockLine
*/
protected function parse($docBlockLine)
{
$this->content = trim($docBlockLine);
$this->values = explode($this->contentSplitCharacter, $docBlockLine);
}
}

View File

@@ -0,0 +1,74 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Reflection\DocBlock\Tag;
class LicenseTag implements TagInterface
{
/**
* @var string
*/
protected $url = null;
/**
* @var string
*/
protected $licenseName = null;
/**
* @return string
*/
public function getName()
{
return 'license';
}
/**
* Initializer
*
* @param string $tagDocblockLine
*/
public function initialize($tagDocblockLine)
{
$match = array();
if (!preg_match('#^([\S]*)(?:\s+(.*))?$#m', $tagDocblockLine, $match)) {
return;
}
if ($match[1] !== '') {
$this->url = trim($match[1]);
}
if (isset($match[2]) && $match[2] !== '') {
$this->licenseName = $match[2];
}
}
/**
* @return null|string
*/
public function getUrl()
{
return $this->url;
}
/**
* @return null|string
*/
public function getLicenseName()
{
return $this->licenseName;
}
public function __toString()
{
return 'DocBlock Tag [ * @' . $this->getName() . ' ]' . PHP_EOL;
}
}

View File

@@ -0,0 +1,122 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Reflection\DocBlock\Tag;
class MethodTag implements TagInterface, PhpDocTypedTagInterface
{
/**
* Return value type
*
* @var array
*/
protected $types = array();
/**
* @var string
*/
protected $methodName = null;
/**
* @var string
*/
protected $description = null;
/**
* Is static method
*
* @var bool
*/
protected $isStatic = false;
/**
* @return string
*/
public function getName()
{
return 'method';
}
/**
* Initializer
*
* @param string $tagDocblockLine
*/
public function initialize($tagDocblockLine)
{
$match = array();
if (!preg_match('#^(static[\s]+)?(.+[\s]+)?(.+\(\))[\s]*(.*)$#m', $tagDocblockLine, $match)) {
return;
}
if ($match[1] !== '') {
$this->isStatic = true;
}
if ($match[2] !== '') {
$this->types = explode('|', rtrim($match[2]));
}
$this->methodName = $match[3];
if ($match[4] !== '') {
$this->description = $match[4];
}
}
/**
* Get return value type
*
* @return null|string
* @deprecated 2.0.4 use getTypes instead
*/
public function getReturnType()
{
if (empty($this->types)) {
return;
}
return $this->types[0];
}
public function getTypes()
{
return $this->types;
}
/**
* @return string
*/
public function getMethodName()
{
return $this->methodName;
}
/**
* @return null|string
*/
public function getDescription()
{
return $this->description;
}
/**
* @return bool
*/
public function isStatic()
{
return $this->isStatic;
}
public function __toString()
{
return 'DocBlock Tag [ * @' . $this->getName() . ' ]' . PHP_EOL;
}
}

View File

@@ -0,0 +1,98 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Reflection\DocBlock\Tag;
class ParamTag implements TagInterface, PhpDocTypedTagInterface
{
/**
* @var array
*/
protected $types = array();
/**
* @var string
*/
protected $variableName = null;
/**
* @var string
*/
protected $description = null;
/**
* @return string
*/
public function getName()
{
return 'param';
}
/**
* Initializer
*
* @param string $tagDocBlockLine
*/
public function initialize($tagDocBlockLine)
{
$matches = array();
if (!preg_match('#((?:[\w|\\\]+(?:\[\])*\|?)+)(?:\s+(\$\S+))?(?:\s+(.*))?#s', $tagDocBlockLine, $matches)) {
return;
}
$this->types = explode('|', $matches[1]);
if (isset($matches[2])) {
$this->variableName = $matches[2];
}
if (isset($matches[3])) {
$this->description = trim(preg_replace('#\s+#', ' ', $matches[3]));
}
}
/**
* Get parameter variable type
*
* @return string
* @deprecated 2.0.4 use getTypes instead
*/
public function getType()
{
if (empty($this->types)) {
return '';
}
return $this->types[0];
}
public function getTypes()
{
return $this->types;
}
/**
* Get parameter name
*
* @return string
*/
public function getVariableName()
{
return $this->variableName;
}
/**
* @return string
*/
public function getDescription()
{
return $this->description;
}
}

View File

@@ -0,0 +1,20 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Reflection\DocBlock\Tag;
interface PhpDocTypedTagInterface
{
/**
* Return all types supported by the tag definition
*
* @return string[]
*/
public function getTypes();
}

View File

@@ -0,0 +1,100 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Reflection\DocBlock\Tag;
class PropertyTag implements TagInterface, PhpDocTypedTagInterface
{
/**
* @var array
*/
protected $types = array();
/**
* @var string
*/
protected $propertyName = null;
/**
* @var string
*/
protected $description = null;
/**
* @return string
*/
public function getName()
{
return 'property';
}
/**
* Initializer
*
* @param string $tagDocblockLine
*/
public function initialize($tagDocblockLine)
{
$match = array();
if (!preg_match('#^(.+)?(\$[\S]+)[\s]*(.*)$#m', $tagDocblockLine, $match)) {
return;
}
if ($match[1] !== '') {
$this->types = explode('|', rtrim($match[1]));
}
if ($match[2] !== '') {
$this->propertyName = $match[2];
}
if ($match[3] !== '') {
$this->description = $match[3];
}
}
/**
* @return null|string
* @deprecated 2.0.4 use getTypes instead
*/
public function getType()
{
if (empty($this->types)) {
return;
}
return $this->types[0];
}
public function getTypes()
{
return $this->types;
}
/**
* @return null|string
*/
public function getPropertyName()
{
return $this->propertyName;
}
/**
* @return null|string
*/
public function getDescription()
{
return $this->description;
}
public function __toString()
{
return 'DocBlock Tag [ * @' . $this->getName() . ' ]' . PHP_EOL;
}
}

View File

@@ -0,0 +1,75 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Reflection\DocBlock\Tag;
class ReturnTag implements TagInterface, PhpDocTypedTagInterface
{
/**
* @var array
*/
protected $types = array();
/**
* @var string
*/
protected $description = null;
/**
* @return string
*/
public function getName()
{
return 'return';
}
/**
* @param string $tagDocBlockLine
* @return void
*/
public function initialize($tagDocBlockLine)
{
$matches = array();
if (!preg_match('#((?:[\w|\\\]+(?:\[\])*\|?)+)(?:\s+(.*))?#s', $tagDocBlockLine, $matches)) {
return;
}
$this->types = explode('|', $matches[1]);
if (isset($matches[2])) {
$this->description = trim(preg_replace('#\s+#', ' ', $matches[2]));
}
}
/**
* @return string
* @deprecated 2.0.4 use getTypes instead
*/
public function getType()
{
if (empty($this->types)) {
return '';
}
return $this->types[0];
}
public function getTypes()
{
return $this->types;
}
/**
* @return string
*/
public function getDescription()
{
return $this->description;
}
}

View File

@@ -0,0 +1,21 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Reflection\DocBlock\Tag;
use Zend\Code\Generic\Prototype\PrototypeInterface;
interface TagInterface extends PrototypeInterface
{
/**
* @param string $content
* @return void
*/
public function initialize($content);
}

View File

@@ -0,0 +1,74 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Reflection\DocBlock\Tag;
class ThrowsTag implements TagInterface, PhpDocTypedTagInterface
{
/**
* @var array
*/
protected $types = array();
/**
* @var string
*/
protected $description = null;
/**
* @return string
*/
public function getName()
{
return 'throws';
}
/**
* @param string $tagDocBlockLine
* @return void
*/
public function initialize($tagDocBlockLine)
{
$matches = array();
preg_match('#([\w|\\\]+)(?:\s+(.*))?#', $tagDocBlockLine, $matches);
$this->types = explode('|', $matches[1]);
if (isset($matches[2])) {
$this->description = $matches[2];
}
}
/**
* Get return variable type
*
* @return string
* @deprecated 2.0.4 use getTypes instead
*/
public function getType()
{
return implode('|', $this->getTypes());
}
/**
* @return array
*/
public function getTypes()
{
return $this->types;
}
/**
* @return string
*/
public function getDescription()
{
return $this->description;
}
}

View File

@@ -0,0 +1,48 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Reflection\DocBlock;
use Zend\Code\Generic\Prototype\PrototypeClassFactory;
use Zend\Code\Reflection\DocBlock\Tag\TagInterface;
class TagManager extends PrototypeClassFactory
{
/**
* @return void
*/
public function initializeDefaultTags()
{
$this->addPrototype(new Tag\ParamTag());
$this->addPrototype(new Tag\ReturnTag());
$this->addPrototype(new Tag\MethodTag());
$this->addPrototype(new Tag\PropertyTag());
$this->addPrototype(new Tag\AuthorTag());
$this->addPrototype(new Tag\LicenseTag());
$this->addPrototype(new Tag\ThrowsTag());
$this->setGenericPrototype(new Tag\GenericTag());
}
/**
* @param string $tagName
* @param string $content
* @return TagInterface
*/
public function createTag($tagName, $content = null)
{
/* @var TagInterface $newTag */
$newTag = $this->getClonedPrototype($tagName);
if ($content) {
$newTag->initialize($content);
}
return $newTag;
}
}

View File

@@ -0,0 +1,296 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Reflection;
use Reflector;
use Zend\Code\Reflection\DocBlock\Tag\TagInterface as DocBlockTagInterface;
use Zend\Code\Reflection\DocBlock\TagManager as DocBlockTagManager;
use Zend\Code\Scanner\DocBlockScanner;
class DocBlockReflection implements ReflectionInterface
{
/**
* @var Reflector
*/
protected $reflector = null;
/**
* @var string
*/
protected $docComment = null;
/**
* @var DocBlockTagManager
*/
protected $tagManager = null;
/**#@+
* @var int
*/
protected $startLine = null;
protected $endLine = null;
/**#@-*/
/**
* @var string
*/
protected $cleanDocComment = null;
/**
* @var string
*/
protected $longDescription = null;
/**
* @var string
*/
protected $shortDescription = null;
/**
* @var array
*/
protected $tags = array();
/**
* @var bool
*/
protected $isReflected = false;
/**
* Export reflection
*
* Required by the Reflector interface.
*
* @todo What should this do?
* @return void
*/
public static function export()
{
}
/**
* @param Reflector|string $commentOrReflector
* @param null|DocBlockTagManager $tagManager
* @throws Exception\InvalidArgumentException
* @return DocBlockReflection
*/
public function __construct($commentOrReflector, DocBlockTagManager $tagManager = null)
{
if (!$tagManager) {
$tagManager = new DocBlockTagManager();
$tagManager->initializeDefaultTags();
}
$this->tagManager = $tagManager;
if ($commentOrReflector instanceof Reflector) {
$this->reflector = $commentOrReflector;
if (!method_exists($commentOrReflector, 'getDocComment')) {
throw new Exception\InvalidArgumentException('Reflector must contain method "getDocComment"');
}
/* @var MethodReflection $commentOrReflector */
$this->docComment = $commentOrReflector->getDocComment();
// determine line numbers
$lineCount = substr_count($this->docComment, "\n");
$this->startLine = $this->reflector->getStartLine() - $lineCount - 1;
$this->endLine = $this->reflector->getStartLine() - 1;
} elseif (is_string($commentOrReflector)) {
$this->docComment = $commentOrReflector;
} else {
throw new Exception\InvalidArgumentException(sprintf(
'%s must have a (string) DocComment or a Reflector in the constructor',
get_class($this)
));
}
if ($this->docComment == '') {
throw new Exception\InvalidArgumentException('DocComment cannot be empty');
}
$this->reflect();
}
/**
* Retrieve contents of DocBlock
*
* @return string
*/
public function getContents()
{
$this->reflect();
return $this->cleanDocComment;
}
/**
* Get start line (position) of DocBlock
*
* @return int
*/
public function getStartLine()
{
$this->reflect();
return $this->startLine;
}
/**
* Get last line (position) of DocBlock
*
* @return int
*/
public function getEndLine()
{
$this->reflect();
return $this->endLine;
}
/**
* Get DocBlock short description
*
* @return string
*/
public function getShortDescription()
{
$this->reflect();
return $this->shortDescription;
}
/**
* Get DocBlock long description
*
* @return string
*/
public function getLongDescription()
{
$this->reflect();
return $this->longDescription;
}
/**
* Does the DocBlock contain the given annotation tag?
*
* @param string $name
* @return bool
*/
public function hasTag($name)
{
$this->reflect();
foreach ($this->tags as $tag) {
if ($tag->getName() == $name) {
return true;
}
}
return false;
}
/**
* Retrieve the given DocBlock tag
*
* @param string $name
* @return DocBlockTagInterface|false
*/
public function getTag($name)
{
$this->reflect();
foreach ($this->tags as $tag) {
if ($tag->getName() == $name) {
return $tag;
}
}
return false;
}
/**
* Get all DocBlock annotation tags
*
* @param string $filter
* @return DocBlockTagInterface[]
*/
public function getTags($filter = null)
{
$this->reflect();
if ($filter === null || !is_string($filter)) {
return $this->tags;
}
$returnTags = array();
foreach ($this->tags as $tag) {
if ($tag->getName() == $filter) {
$returnTags[] = $tag;
}
}
return $returnTags;
}
/**
* Parse the DocBlock
*
* @return void
*/
protected function reflect()
{
if ($this->isReflected) {
return;
}
$docComment = preg_replace('#[ ]{0,1}\*/$#', '', $this->docComment);
// create a clean docComment
$this->cleanDocComment = preg_replace("#[ \t]*(?:/\*\*|\*/|\*)[ ]{0,1}(.*)?#", '$1', $docComment);
$this->cleanDocComment = ltrim($this->cleanDocComment, "\r\n"); // @todo should be changed to remove first and last empty line
$scanner = new DocBlockScanner($docComment);
$this->shortDescription = ltrim($scanner->getShortDescription());
$this->longDescription = ltrim($scanner->getLongDescription());
foreach ($scanner->getTags() as $tag) {
$this->tags[] = $this->tagManager->createTag(ltrim($tag['name'], '@'), ltrim($tag['value']));
}
$this->isReflected = true;
}
/**
* @return string
*/
public function toString()
{
$str = "DocBlock [ /* DocBlock */ ] {" . PHP_EOL . PHP_EOL;
$str .= " - Tags [" . count($this->tags) . "] {" . PHP_EOL;
foreach ($this->tags as $tag) {
$str .= " " . $tag;
}
$str .= " }" . PHP_EOL;
$str .= "}" . PHP_EOL;
return $str;
}
/**
* Serialize to string
*
* Required by the Reflector interface
*
* @return string
*/
public function __toString()
{
return $this->toString();
}
}

View File

@@ -0,0 +1,17 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Reflection\Exception;
use Zend\Code\Exception;
class BadMethodCallException extends Exception\BadMethodCallException implements
ExceptionInterface
{
}

View File

@@ -0,0 +1,16 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Reflection\Exception;
use Zend\Code\Exception\ExceptionInterface as Exception;
interface ExceptionInterface extends Exception
{
}

View File

@@ -0,0 +1,17 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Reflection\Exception;
use Zend\Code\Exception;
class InvalidArgumentException extends Exception\InvalidArgumentException implements
ExceptionInterface
{
}

View File

@@ -0,0 +1,17 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Reflection\Exception;
use Zend\Code\Exception;
class RuntimeException extends Exception\RuntimeException implements
ExceptionInterface
{
}

View File

@@ -0,0 +1,317 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Reflection;
use Zend\Code\Scanner\CachingFileScanner;
class FileReflection implements ReflectionInterface
{
/**
* @var string
*/
protected $filePath = null;
/**
* @var string
*/
protected $docComment = null;
/**
* @var int
*/
protected $startLine = 1;
/**
* @var int
*/
protected $endLine = null;
/**
* @var string[]
*/
protected $namespaces = array();
/**
* @var string[]
*/
protected $uses = array();
/**
* @var string[]
*/
protected $requiredFiles = array();
/**
* @var ClassReflection[]
*/
protected $classes = array();
/**
* @var FunctionReflection[]
*/
protected $functions = array();
/**
* @var string
*/
protected $contents = null;
/**
* @param string $filename
* @param bool $includeIfNotAlreadyIncluded
* @throws Exception\InvalidArgumentException If file does not exists
* @throws Exception\RuntimeException If file exists but is not included or required
*/
public function __construct($filename, $includeIfNotAlreadyIncluded = false)
{
if (($fileRealPath = realpath($filename)) === false) {
$fileRealPath = stream_resolve_include_path($filename);
}
if (!$fileRealPath) {
throw new Exception\InvalidArgumentException(sprintf(
'No file for %s was found.',
$filename
));
}
if (!in_array($fileRealPath, get_included_files())) {
if (!$includeIfNotAlreadyIncluded) {
throw new Exception\RuntimeException(sprintf(
'File %s must be required before it can be reflected',
$filename
));
}
include $fileRealPath;
}
$this->filePath = $fileRealPath;
$this->reflect();
}
/**
* Required by the Reflector interface.
*
* @todo What should this do?
* @return null
*/
public static function export()
{
return;
}
/**
* Return the file name of the reflected file
*
* @return string
*/
public function getFileName()
{
return basename($this->filePath);
}
/**
* Get the start line - Always 1, staying consistent with the Reflection API
*
* @return int
*/
public function getStartLine()
{
return $this->startLine;
}
/**
* Get the end line / number of lines
*
* @return int
*/
public function getEndLine()
{
return $this->endLine;
}
/**
* @return string
*/
public function getDocComment()
{
return $this->docComment;
}
/**
* @return DocBlockReflection
*/
public function getDocBlock()
{
if (!($docComment = $this->getDocComment())) {
return false;
}
$instance = new DocBlockReflection($docComment);
return $instance;
}
/**
* @return string[]
*/
public function getNamespaces()
{
return $this->namespaces;
}
/**
* @return string
*/
public function getNamespace()
{
if (count($this->namespaces) == 0) {
return;
}
return $this->namespaces[0];
}
/**
* @return array
*/
public function getUses()
{
return $this->uses;
}
/**
* Return the reflection classes of the classes found inside this file
*
* @return ClassReflection[]
*/
public function getClasses()
{
$classes = array();
foreach ($this->classes as $class) {
$classes[] = new ClassReflection($class);
}
return $classes;
}
/**
* Return the reflection functions of the functions found inside this file
*
* @return FunctionReflection[]
*/
public function getFunctions()
{
$functions = array();
foreach ($this->functions as $function) {
$functions[] = new FunctionReflection($function);
}
return $functions;
}
/**
* Retrieve the reflection class of a given class found in this file
*
* @param null|string $name
* @return ClassReflection
* @throws Exception\InvalidArgumentException for invalid class name or invalid reflection class
*/
public function getClass($name = null)
{
if (null === $name) {
reset($this->classes);
$selected = current($this->classes);
return new ClassReflection($selected);
}
if (in_array($name, $this->classes)) {
return new ClassReflection($name);
}
throw new Exception\InvalidArgumentException(sprintf(
'Class by name %s not found.',
$name
));
}
/**
* Return the full contents of file
*
* @return string
*/
public function getContents()
{
return file_get_contents($this->filePath);
}
public function toString()
{
return ''; // @todo
}
/**
* Serialize to string
*
* Required by the Reflector interface
*
* @todo What should this serialization look like?
* @return string
*/
public function __toString()
{
return '';
}
/**
* This method does the work of "reflecting" the file
*
* Uses Zend\Code\Scanner\FileScanner to gather file information
*
* @return void
*/
protected function reflect()
{
$scanner = new CachingFileScanner($this->filePath);
$this->docComment = $scanner->getDocComment();
$this->requiredFiles = $scanner->getIncludes();
$this->classes = $scanner->getClassNames();
$this->namespaces = $scanner->getNamespaces();
$this->uses = $scanner->getUses();
}
/**
* Validate / check a file level DocBlock
*
* @param array $tokens Array of tokenizer tokens
* @return void
*/
protected function checkFileDocBlock($tokens)
{
foreach ($tokens as $token) {
$type = $token[0];
$value = $token[1];
$lineNum = $token[2];
if (($type == T_OPEN_TAG) || ($type == T_WHITESPACE)) {
continue;
} elseif ($type == T_DOC_COMMENT) {
$this->docComment = $value;
$this->startLine = $lineNum + substr_count($value, "\n") + 1;
return;
} else {
// Only whitespace is allowed before file DocBlocks
return;
}
}
}
}

View File

@@ -0,0 +1,269 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Reflection;
use ReflectionFunction;
class FunctionReflection extends ReflectionFunction implements ReflectionInterface
{
/**
* Constant use in @MethodReflection to display prototype as an array
*/
const PROTOTYPE_AS_ARRAY = 'prototype_as_array';
/**
* Constant use in @MethodReflection to display prototype as a string
*/
const PROTOTYPE_AS_STRING = 'prototype_as_string';
/**
* Get function DocBlock
*
* @throws Exception\InvalidArgumentException
* @return DocBlockReflection
*/
public function getDocBlock()
{
if ('' == ($comment = $this->getDocComment())) {
throw new Exception\InvalidArgumentException(sprintf(
'%s does not have a DocBlock',
$this->getName()
));
}
$instance = new DocBlockReflection($comment);
return $instance;
}
/**
* Get start line (position) of function
*
* @param bool $includeDocComment
* @return int
*/
public function getStartLine($includeDocComment = false)
{
if ($includeDocComment) {
if ($this->getDocComment() != '') {
return $this->getDocBlock()->getStartLine();
}
}
return parent::getStartLine();
}
/**
* Get contents of function
*
* @param bool $includeDocBlock
* @return string
*/
public function getContents($includeDocBlock = true)
{
$fileName = $this->getFileName();
if (false === $fileName) {
return '';
}
$startLine = $this->getStartLine();
$endLine = $this->getEndLine();
// eval'd protect
if (preg_match('#\((\d+)\) : eval\(\)\'d code$#', $fileName, $matches)) {
$fileName = preg_replace('#\(\d+\) : eval\(\)\'d code$#', '', $fileName);
$startLine = $endLine = $matches[1];
}
$lines = array_slice(
file($fileName, FILE_IGNORE_NEW_LINES),
$startLine - 1,
($endLine - ($startLine - 1)),
true
);
$functionLine = implode("\n", $lines);
$content = '';
if ($this->isClosure()) {
preg_match('#function\s*\([^\)]*\)\s*(use\s*\([^\)]+\))?\s*\{(.*\;)?\s*\}#s', $functionLine, $matches);
if (isset($matches[0])) {
$content = $matches[0];
}
} else {
$name = substr($this->getName(), strrpos($this->getName(), '\\')+1);
preg_match('#function\s+' . preg_quote($name) . '\s*\([^\)]*\)\s*{([^{}]+({[^}]+})*[^}]+)?}#', $functionLine, $matches);
if (isset($matches[0])) {
$content = $matches[0];
}
}
$docComment = $this->getDocComment();
return $includeDocBlock && $docComment ? $docComment . "\n" . $content : $content;
}
/**
* Get method prototype
*
* @return array
*/
public function getPrototype($format = FunctionReflection::PROTOTYPE_AS_ARRAY)
{
$returnType = 'mixed';
$docBlock = $this->getDocBlock();
if ($docBlock) {
$return = $docBlock->getTag('return');
$returnTypes = $return->getTypes();
$returnType = count($returnTypes) > 1 ? implode('|', $returnTypes) : $returnTypes[0];
}
$prototype = array(
'namespace' => $this->getNamespaceName(),
'name' => substr($this->getName(), strlen($this->getNamespaceName()) + 1),
'return' => $returnType,
'arguments' => array(),
);
$parameters = $this->getParameters();
foreach ($parameters as $parameter) {
$prototype['arguments'][$parameter->getName()] = array(
'type' => $parameter->getType(),
'required' => !$parameter->isOptional(),
'by_ref' => $parameter->isPassedByReference(),
'default' => $parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null,
);
}
if ($format == FunctionReflection::PROTOTYPE_AS_STRING) {
$line = $prototype['return'] . ' ' . $prototype['name'] . '(';
$args = array();
foreach ($prototype['arguments'] as $name => $argument) {
$argsLine = ($argument['type'] ? $argument['type'] . ' ' : '') . ($argument['by_ref'] ? '&' : '') . '$' . $name;
if (!$argument['required']) {
$argsLine .= ' = ' . var_export($argument['default'], true);
}
$args[] = $argsLine;
}
$line .= implode(', ', $args);
$line .= ')';
return $line;
}
return $prototype;
}
/**
* Get function parameters
*
* @return ParameterReflection[]
*/
public function getParameters()
{
$phpReflections = parent::getParameters();
$zendReflections = array();
while ($phpReflections && ($phpReflection = array_shift($phpReflections))) {
$instance = new ParameterReflection($this->getName(), $phpReflection->getName());
$zendReflections[] = $instance;
unset($phpReflection);
}
unset($phpReflections);
return $zendReflections;
}
/**
* Get return type tag
*
* @throws Exception\InvalidArgumentException
* @return DocBlockReflection
*/
public function getReturn()
{
$docBlock = $this->getDocBlock();
if (!$docBlock->hasTag('return')) {
throw new Exception\InvalidArgumentException(
'Function does not specify an @return annotation tag; cannot determine return type'
);
}
$tag = $docBlock->getTag('return');
return new DocBlockReflection('@return ' . $tag->getDescription());
}
/**
* Get method body
*
* @return string|false
*/
public function getBody()
{
$fileName = $this->getFileName();
if (false === $fileName) {
throw new Exception\InvalidArgumentException(
'Cannot determine internals functions body'
);
}
$startLine = $this->getStartLine();
$endLine = $this->getEndLine();
// eval'd protect
if (preg_match('#\((\d+)\) : eval\(\)\'d code$#', $fileName, $matches)) {
$fileName = preg_replace('#\(\d+\) : eval\(\)\'d code$#', '', $fileName);
$startLine = $endLine = $matches[1];
}
$lines = array_slice(
file($fileName, FILE_IGNORE_NEW_LINES),
$startLine - 1,
($endLine - ($startLine - 1)),
true
);
$functionLine = implode("\n", $lines);
$body = false;
if ($this->isClosure()) {
preg_match('#function\s*\([^\)]*\)\s*(use\s*\([^\)]+\))?\s*\{(.*\;)\s*\}#s', $functionLine, $matches);
if (isset($matches[2])) {
$body = $matches[2];
}
} else {
$name = substr($this->getName(), strrpos($this->getName(), '\\')+1);
preg_match('#function\s+' . $name . '\s*\([^\)]*\)\s*{([^{}]+({[^}]+})*[^}]+)}#', $functionLine, $matches);
if (isset($matches[1])) {
$body = $matches[1];
}
}
return $body;
}
/**
* @return string
*/
public function toString()
{
return $this->__toString();
}
/**
* Required due to bug in php
*
* @return string
*/
public function __toString()
{
return parent::__toString();
}
}

View File

@@ -0,0 +1,494 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Reflection;
use ReflectionMethod as PhpReflectionMethod;
use Zend\Code\Annotation\AnnotationManager;
use Zend\Code\Scanner\AnnotationScanner;
use Zend\Code\Scanner\CachingFileScanner;
class MethodReflection extends PhpReflectionMethod implements ReflectionInterface
{
/**
* Constant use in @MethodReflection to display prototype as an array
*/
const PROTOTYPE_AS_ARRAY = 'prototype_as_array';
/**
* Constant use in @MethodReflection to display prototype as a string
*/
const PROTOTYPE_AS_STRING = 'prototype_as_string';
/**
* @var AnnotationScanner
*/
protected $annotations = null;
/**
* Retrieve method DocBlock reflection
*
* @return DocBlockReflection|false
*/
public function getDocBlock()
{
if ('' == $this->getDocComment()) {
return false;
}
$instance = new DocBlockReflection($this);
return $instance;
}
/**
* @param AnnotationManager $annotationManager
* @return AnnotationScanner
*/
public function getAnnotations(AnnotationManager $annotationManager)
{
if (($docComment = $this->getDocComment()) == '') {
return false;
}
if ($this->annotations) {
return $this->annotations;
}
$cachingFileScanner = $this->createFileScanner($this->getFileName());
$nameInformation = $cachingFileScanner->getClassNameInformation($this->getDeclaringClass()->getName());
if (!$nameInformation) {
return false;
}
$this->annotations = new AnnotationScanner($annotationManager, $docComment, $nameInformation);
return $this->annotations;
}
/**
* Get start line (position) of method
*
* @param bool $includeDocComment
* @return int
*/
public function getStartLine($includeDocComment = false)
{
if ($includeDocComment) {
if ($this->getDocComment() != '') {
return $this->getDocBlock()->getStartLine();
}
}
return parent::getStartLine();
}
/**
* Get reflection of declaring class
*
* @return ClassReflection
*/
public function getDeclaringClass()
{
$phpReflection = parent::getDeclaringClass();
$zendReflection = new ClassReflection($phpReflection->getName());
unset($phpReflection);
return $zendReflection;
}
/**
* Get method prototype
*
* @return array
*/
public function getPrototype($format = MethodReflection::PROTOTYPE_AS_ARRAY)
{
$returnType = 'mixed';
$docBlock = $this->getDocBlock();
if ($docBlock) {
$return = $docBlock->getTag('return');
$returnTypes = $return->getTypes();
$returnType = count($returnTypes) > 1 ? implode('|', $returnTypes) : $returnTypes[0];
}
$declaringClass = $this->getDeclaringClass();
$prototype = array(
'namespace' => $declaringClass->getNamespaceName(),
'class' => substr($declaringClass->getName(), strlen($declaringClass->getNamespaceName()) + 1),
'name' => $this->getName(),
'visibility' => ($this->isPublic() ? 'public' : ($this->isPrivate() ? 'private' : 'protected')),
'return' => $returnType,
'arguments' => array(),
);
$parameters = $this->getParameters();
foreach ($parameters as $parameter) {
$prototype['arguments'][$parameter->getName()] = array(
'type' => $parameter->getType(),
'required' => !$parameter->isOptional(),
'by_ref' => $parameter->isPassedByReference(),
'default' => $parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null,
);
}
if ($format == MethodReflection::PROTOTYPE_AS_STRING) {
$line = $prototype['visibility'] . ' ' . $prototype['return'] . ' ' . $prototype['name'] . '(';
$args = array();
foreach ($prototype['arguments'] as $name => $argument) {
$argsLine = ($argument['type'] ? $argument['type'] . ' ' : '') . ($argument['by_ref'] ? '&' : '') . '$' . $name;
if (!$argument['required']) {
$argsLine .= ' = ' . var_export($argument['default'], true);
}
$args[] = $argsLine;
}
$line .= implode(', ', $args);
$line .= ')';
return $line;
}
return $prototype;
}
/**
* Get all method parameter reflection objects
*
* @return ParameterReflection[]
*/
public function getParameters()
{
$phpReflections = parent::getParameters();
$zendReflections = array();
while ($phpReflections && ($phpReflection = array_shift($phpReflections))) {
$instance = new ParameterReflection(
array($this->getDeclaringClass()->getName(), $this->getName()),
$phpReflection->getName()
);
$zendReflections[] = $instance;
unset($phpReflection);
}
unset($phpReflections);
return $zendReflections;
}
/**
* Get method contents
*
* @param bool $includeDocBlock
* @return string
*/
public function getContents($includeDocBlock = true)
{
$docComment = $this->getDocComment();
$content = ($includeDocBlock && !empty($docComment)) ? $docComment . "\n" : '';
$content .= $this->extractMethodContents();
return $content;
}
/**
* Get method body
*
* @return string
*/
public function getBody()
{
return $this->extractMethodContents(true);
}
/**
* Tokenize method string and return concatenated body
*
* @param bool $bodyOnly
* @return string
*/
protected function extractMethodContents($bodyOnly = false)
{
$fileName = $this->getFileName();
if ((class_exists($this->class) && false === $fileName) || ! file_exists($fileName)) {
return '';
}
$lines = array_slice(
file($fileName, FILE_IGNORE_NEW_LINES),
$this->getStartLine() - 1,
($this->getEndLine() - ($this->getStartLine() - 1)),
true
);
$functionLine = implode("\n", $lines);
$tokens = token_get_all("<?php ". $functionLine);
//remove first entry which is php open tag
array_shift($tokens);
if (!count($tokens)) {
return '';
}
$capture = false;
$firstBrace = false;
$body = '';
foreach ($tokens as $key => $token) {
$tokenType = (is_array($token)) ? token_name($token[0]) : $token;
$tokenValue = (is_array($token)) ? $token[1] : $token;
switch ($tokenType) {
case "T_FINAL":
case "T_ABSTRACT":
case "T_PUBLIC":
case "T_PROTECTED":
case "T_PRIVATE":
case "T_STATIC":
case "T_FUNCTION":
// check to see if we have a valid function
// then check if we are inside function and have a closure
if ($this->isValidFunction($tokens, $key, $this->getName())) {
if ($bodyOnly === false) {
//if first instance of tokenType grab prefixed whitespace
//and append to body
if ($capture === false) {
$body .= $this->extractPrefixedWhitespace($tokens, $key);
}
$body .= $tokenValue;
}
$capture = true;
} else {
//closure test
if ($firstBrace && $tokenType == "T_FUNCTION") {
$body .= $tokenValue;
continue;
}
$capture = false;
continue;
}
break;
case "{":
if ($capture === false) {
continue;
}
if ($firstBrace === false) {
$firstBrace = true;
if ($bodyOnly === true) {
continue;
}
}
$body .= $tokenValue;
break;
case "}":
if ($capture === false) {
continue;
}
//check to see if this is the last brace
if ($this->isEndingBrace($tokens, $key)) {
//capture the end brace if not bodyOnly
if ($bodyOnly === false) {
$body .= $tokenValue;
}
break 2;
}
$body .= $tokenValue;
break;
default:
if ($capture === false) {
continue;
}
// if returning body only wait for first brace before capturing
if ($bodyOnly === true && $firstBrace !== true) {
continue;
}
$body .= $tokenValue;
break;
}
}
//remove ending whitespace and return
return rtrim($body);
}
/**
* Take current position and find any whitespace
*
* @param array $haystack
* @param int $position
* @return string
*/
protected function extractPrefixedWhitespace($haystack, $position)
{
$content = '';
$count = count($haystack);
if ($position+1 == $count) {
return $content;
}
for ($i = $position-1;$i >= 0;$i--) {
$tokenType = (is_array($haystack[$i])) ? token_name($haystack[$i][0]) : $haystack[$i];
$tokenValue = (is_array($haystack[$i])) ? $haystack[$i][1] : $haystack[$i];
//search only for whitespace
if ($tokenType == "T_WHITESPACE") {
$content .= $tokenValue;
} else {
break;
}
}
return $content;
}
/**
* Test for ending brace
*
* @param array $haystack
* @param int $position
* @return bool
*/
protected function isEndingBrace($haystack, $position)
{
$count = count($haystack);
//advance one position
$position = $position+1;
if ($position == $count) {
return true;
}
for ($i = $position;$i < $count; $i++) {
$tokenType = (is_array($haystack[$i])) ? token_name($haystack[$i][0]) : $haystack[$i];
switch ($tokenType) {
case "T_FINAL":
case "T_ABSTRACT":
case "T_PUBLIC":
case "T_PROTECTED":
case "T_PRIVATE":
case "T_STATIC":
return true;
case "T_FUNCTION":
// If a function is encountered and that function is not a closure
// then return true. otherwise the function is a closure, return false
if ($this->isValidFunction($haystack, $i)) {
return true;
}
return false;
case "}":
case ";";
case "T_BREAK":
case "T_CATCH":
case "T_DO":
case "T_ECHO":
case "T_ELSE":
case "T_ELSEIF":
case "T_EVAL":
case "T_EXIT":
case "T_FINALLY":
case "T_FOR":
case "T_FOREACH":
case "T_GOTO":
case "T_IF":
case "T_INCLUDE":
case "T_INCLUDE_ONCE":
case "T_PRINT":
case "T_STRING":
case "T_STRING_VARNAME":
case "T_THROW":
case "T_USE":
case "T_VARIABLE":
case "T_WHILE":
case "T_YIELD":
return false;
}
}
}
/**
* Test to see if current position is valid function or
* closure. Returns true if it's a function and NOT a closure
*
* @param array $haystack
* @param int $position
* @param string $functionName
* @return bool
*/
protected function isValidFunction($haystack, $position, $functionName = null)
{
$isValid = false;
$count = count($haystack);
for ($i = $position+1; $i < $count; $i++) {
$tokenType = (is_array($haystack[$i])) ? token_name($haystack[$i][0]) : $haystack[$i];
$tokenValue = (is_array($haystack[$i])) ? $haystack[$i][1] : $haystack[$i];
//check for occurance of ( or
if ($tokenType == "T_STRING") {
//check to see if function name is passed, if so validate against that
if ($functionName !== null && $tokenValue != $functionName) {
$isValid = false;
break;
}
$isValid = true;
break;
} elseif ($tokenValue == "(") {
break;
}
}
return $isValid;
}
/**
* @return string
*/
public function toString()
{
return parent::__toString();
}
/**
* @return string
*/
public function __toString()
{
return parent::__toString();
}
/**
* Creates a new FileScanner instance.
*
* By having this as a seperate method it allows the method to be overridden
* if a different FileScanner is needed.
*
* @param string $filename
*
* @return CachingFileScanner
*/
protected function createFileScanner($filename)
{
return new CachingFileScanner($filename);
}
}

View File

@@ -0,0 +1,116 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Reflection;
use ReflectionParameter;
class ParameterReflection extends ReflectionParameter implements ReflectionInterface
{
/**
* @var bool
*/
protected $isFromMethod = false;
/**
* Get declaring class reflection object
*
* @return ClassReflection
*/
public function getDeclaringClass()
{
$phpReflection = parent::getDeclaringClass();
$zendReflection = new ClassReflection($phpReflection->getName());
unset($phpReflection);
return $zendReflection;
}
/**
* Get class reflection object
*
* @return ClassReflection
*/
public function getClass()
{
$phpReflection = parent::getClass();
if ($phpReflection === null) {
return;
}
$zendReflection = new ClassReflection($phpReflection->getName());
unset($phpReflection);
return $zendReflection;
}
/**
* Get declaring function reflection object
*
* @return FunctionReflection|MethodReflection
*/
public function getDeclaringFunction()
{
$phpReflection = parent::getDeclaringFunction();
if ($phpReflection instanceof \ReflectionMethod) {
$zendReflection = new MethodReflection($this->getDeclaringClass()->getName(), $phpReflection->getName());
} else {
$zendReflection = new FunctionReflection($phpReflection->getName());
}
unset($phpReflection);
return $zendReflection;
}
/**
* Get parameter type
*
* @return string
*/
public function getType()
{
if ($this->isArray()) {
return 'array';
} elseif (method_exists($this, 'isCallable') && $this->isCallable()) {
return 'callable';
}
if (($class = $this->getClass()) instanceof \ReflectionClass) {
return $class->getName();
}
$docBlock = $this->getDeclaringFunction()->getDocBlock();
if (!$docBlock instanceof DocBlockReflection) {
return;
}
$params = $docBlock->getTags('param');
if (isset($params[$this->getPosition()])) {
return $params[$this->getPosition()]->getType();
}
return;
}
/**
* @return string
*/
public function toString()
{
return parent::__toString();
}
/**
* @return string
*/
public function __toString()
{
return parent::__toString();
}
}

View File

@@ -0,0 +1,114 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Reflection;
use ReflectionProperty as PhpReflectionProperty;
use Zend\Code\Annotation\AnnotationManager;
use Zend\Code\Scanner\AnnotationScanner;
use Zend\Code\Scanner\CachingFileScanner;
/**
* @todo implement line numbers
*/
class PropertyReflection extends PhpReflectionProperty implements ReflectionInterface
{
/**
* @var AnnotationScanner
*/
protected $annotations;
/**
* Get declaring class reflection object
*
* @return ClassReflection
*/
public function getDeclaringClass()
{
$phpReflection = parent::getDeclaringClass();
$zendReflection = new ClassReflection($phpReflection->getName());
unset($phpReflection);
return $zendReflection;
}
/**
* Get DocBlock comment
*
* @return string|false False if no DocBlock defined
*/
public function getDocComment()
{
return parent::getDocComment();
}
/**
* @return false|DocBlockReflection
*/
public function getDocBlock()
{
if (!($docComment = $this->getDocComment())) {
return false;
}
$docBlockReflection = new DocBlockReflection($docComment);
return $docBlockReflection;
}
/**
* @param AnnotationManager $annotationManager
* @return AnnotationScanner
*/
public function getAnnotations(AnnotationManager $annotationManager)
{
if (null !== $this->annotations) {
return $this->annotations;
}
if (($docComment = $this->getDocComment()) == '') {
return false;
}
$class = $this->getDeclaringClass();
$cachingFileScanner = $this->createFileScanner($class->getFileName());
$nameInformation = $cachingFileScanner->getClassNameInformation($class->getName());
if (!$nameInformation) {
return false;
}
$this->annotations = new AnnotationScanner($annotationManager, $docComment, $nameInformation);
return $this->annotations;
}
/**
* @return string
*/
public function toString()
{
return $this->__toString();
}
/**
* Creates a new FileScanner instance.
*
* By having this as a seperate method it allows the method to be overridden
* if a different FileScanner is needed.
*
* @param string $filename
*
* @return CachingFileScanner
*/
protected function createFileScanner($filename)
{
return new CachingFileScanner($filename);
}
}

View File

@@ -0,0 +1,20 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Reflection;
use Reflector;
interface ReflectionInterface extends Reflector
{
/**
* @return string
*/
public function toString();
}

View File

@@ -0,0 +1,117 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Scanner;
use Zend\Code\Exception;
class AggregateDirectoryScanner extends DirectoryScanner
{
/**
* @var bool
*/
protected $isScanned = false;
/**
* @param bool $returnScannerClass
* @todo not implemented
*/
public function getNamespaces($returnScannerClass = false)
{
// @todo
}
/*
public function getUses($returnScannerClass = false)
{}
*/
public function getIncludes($returnScannerClass = false)
{
}
public function getClasses($returnScannerClass = false, $returnDerivedScannerClass = false)
{
$classes = array();
foreach ($this->directories as $scanner) {
$classes += $scanner->getClasses();
}
if ($returnScannerClass) {
foreach ($classes as $index => $class) {
$classes[$index] = $this->getClass($class, $returnScannerClass, $returnDerivedScannerClass);
}
}
return $classes;
}
/**
* @param string $class
* @return bool
*/
public function hasClass($class)
{
foreach ($this->directories as $scanner) {
if ($scanner->hasClass($class)) {
break;
} else {
unset($scanner);
}
}
return (isset($scanner));
}
/**
* @param string $class
* @param bool $returnScannerClass
* @param bool $returnDerivedScannerClass
* @return ClassScanner|DerivedClassScanner
* @throws Exception\RuntimeException
*/
public function getClass($class, $returnScannerClass = true, $returnDerivedScannerClass = false)
{
foreach ($this->directories as $scanner) {
if ($scanner->hasClass($class)) {
break;
} else {
unset($scanner);
}
}
if (!isset($scanner)) {
throw new Exception\RuntimeException('Class by that name was not found.');
}
$classScanner = $scanner->getClass($class);
return new DerivedClassScanner($classScanner, $this);
}
/**
* @param bool $returnScannerClass
*/
public function getFunctions($returnScannerClass = false)
{
$this->scan();
if (!$returnScannerClass) {
$functions = array();
foreach ($this->infos as $info) {
if ($info['type'] == 'function') {
$functions[] = $info['name'];
}
}
return $functions;
}
$scannerClass = new FunctionScanner();
// @todo
}
}

View File

@@ -0,0 +1,353 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Scanner;
use Zend\Code\Annotation\AnnotationCollection;
use Zend\Code\Annotation\AnnotationManager;
use Zend\Code\NameInformation;
class AnnotationScanner extends AnnotationCollection implements ScannerInterface
{
/**
* @var bool
*/
protected $isScanned = false;
/**
* @var string
*/
protected $docComment = null;
/**
* @var NameInformation
*/
protected $nameInformation = null;
/**
* @var AnnotationManager
*/
protected $annotationManager = null;
/**
* @var array
*/
protected $annotations = array();
/**
* @param AnnotationManager $annotationManager
* @param string $docComment
* @param NameInformation $nameInformation
* @return AnnotationScanner
*/
public function __construct(
AnnotationManager $annotationManager,
$docComment,
NameInformation $nameInformation = null
) {
$this->annotationManager = $annotationManager;
$this->docComment = $docComment;
$this->nameInformation = $nameInformation;
$this->scan($this->tokenize());
}
/**
* @param NameInformation $nameInformation
*/
public function setNameInformation(NameInformation $nameInformation)
{
$this->nameInformation = $nameInformation;
}
/**
* @param array $tokens
*/
protected function scan(array $tokens)
{
$annotations = array();
$annotationIndex = -1;
$contentEnd = false;
reset($tokens);
SCANNER_TOP:
$token = current($tokens);
switch ($token[0]) {
case 'ANNOTATION_CLASS':
$contentEnd = false;
$annotationIndex++;
$class = substr($token[1], 1);
$class = $this->nameInformation->resolveName($class);
$annotations[$annotationIndex] = array($class, null);
goto SCANNER_CONTINUE;
// goto no break needed
case 'ANNOTATION_CONTENT_START':
$annotations[$annotationIndex][1] = '';
//fall-through
case 'ANNOTATION_CONTENT_END':
case 'ANNOTATION_CONTENT':
case 'ANNOTATION_WHITESPACE':
case 'ANNOTATION_NEWLINE':
if (!$contentEnd && isset($annotations[$annotationIndex]) && is_string($annotations[$annotationIndex][1])) {
$annotations[$annotationIndex][1] .= $token[1];
}
if ($token[0] === 'ANNOTATION_CONTENT_END') {
$contentEnd = true;
}
goto SCANNER_CONTINUE;
}
SCANNER_CONTINUE:
if (next($tokens) === false) {
goto SCANNER_END;
}
goto SCANNER_TOP;
SCANNER_END:
foreach ($annotations as $annotation) {
$annotation[] = '@' . $annotation[0] . $annotation[1];
$annotationObject = $this->annotationManager->createAnnotation($annotation);
if ($annotationObject) {
$this->append($annotationObject);
}
}
}
/**
* @return array
*/
protected function tokenize()
{
static $CONTEXT_DOCBLOCK = 0x01;
static $CONTEXT_ASTERISK = 0x02;
static $CONTEXT_CLASS = 0x04;
static $CONTEXT_CONTENT = 0x08;
$context = 0x00;
$stream = $this->docComment;
$streamIndex = null;
$tokens = array();
$tokenIndex = null;
$currentChar = null;
$currentWord = null;
$currentLine = null;
$annotationParentCount = 0;
$MACRO_STREAM_ADVANCE_CHAR = function ($positionsForward = 1) use (&$stream, &$streamIndex, &$currentChar, &$currentWord, &$currentLine) {
$positionsForward = ($positionsForward > 0) ? $positionsForward : 1;
$streamIndex = ($streamIndex === null) ? 0 : $streamIndex + $positionsForward;
if (!isset($stream[$streamIndex])) {
$currentChar = false;
return false;
}
$currentChar = $stream[$streamIndex];
$matches = array();
$currentLine = (preg_match('#(.*?)(?:\n|\r\n?)#', $stream, $matches, null, $streamIndex) === 1) ? $matches[1] : substr($stream, $streamIndex);
if ($currentChar === ' ') {
$currentWord = (preg_match('#( +)#', $currentLine, $matches) === 1) ? $matches[1] : $currentLine;
} else {
$currentWord = (($matches = strpos($currentLine, ' ')) !== false) ? substr($currentLine, 0, $matches) : $currentLine;
}
return $currentChar;
};
$MACRO_STREAM_ADVANCE_WORD = function () use (&$currentWord, &$MACRO_STREAM_ADVANCE_CHAR) {
return $MACRO_STREAM_ADVANCE_CHAR(strlen($currentWord));
};
$MACRO_STREAM_ADVANCE_LINE = function () use (&$currentLine, &$MACRO_STREAM_ADVANCE_CHAR) {
return $MACRO_STREAM_ADVANCE_CHAR(strlen($currentLine));
};
$MACRO_TOKEN_ADVANCE = function () use (&$tokenIndex, &$tokens) {
$tokenIndex = ($tokenIndex === null) ? 0 : $tokenIndex + 1;
$tokens[$tokenIndex] = array('ANNOTATION_UNKNOWN', '');
};
$MACRO_TOKEN_SET_TYPE = function ($type) use (&$tokenIndex, &$tokens) {
$tokens[$tokenIndex][0] = $type;
};
$MACRO_TOKEN_APPEND_CHAR = function () use (&$currentChar, &$tokens, &$tokenIndex) {
$tokens[$tokenIndex][1] .= $currentChar;
};
$MACRO_TOKEN_APPEND_WORD = function () use (&$currentWord, &$tokens, &$tokenIndex) {
$tokens[$tokenIndex][1] .= $currentWord;
};
$MACRO_TOKEN_APPEND_LINE = function () use (&$currentLine, &$tokens, &$tokenIndex) {
$tokens[$tokenIndex][1] .= $currentLine;
};
$MACRO_HAS_CONTEXT = function ($which) use (&$context) {
return (($context & $which) === $which);
};
$MACRO_STREAM_ADVANCE_CHAR();
$MACRO_TOKEN_ADVANCE();
TOKENIZER_TOP:
if ($context === 0x00 && $currentChar === '/' && $currentWord === '/**') {
$MACRO_TOKEN_SET_TYPE('ANNOTATION_COMMENTSTART');
$MACRO_TOKEN_APPEND_WORD();
$MACRO_TOKEN_ADVANCE();
$context |= $CONTEXT_DOCBLOCK;
$context |= $CONTEXT_ASTERISK;
if ($MACRO_STREAM_ADVANCE_WORD() === false) {
goto TOKENIZER_END;
}
goto TOKENIZER_TOP;
}
if ($MACRO_HAS_CONTEXT($CONTEXT_CLASS)) {
if (in_array($currentChar, array(' ', '(', "\n", "\r"))) {
$context &= ~$CONTEXT_CLASS;
$MACRO_TOKEN_ADVANCE();
} else {
$MACRO_TOKEN_APPEND_CHAR();
if ($MACRO_STREAM_ADVANCE_CHAR() === false) {
goto TOKENIZER_END;
}
goto TOKENIZER_TOP;
}
}
// Since we don't know what line endings are used in the file, we check for all scenarios. If we find a
// cariage return (\r), we check the next character for a line feed (\n). If so we consume it and act as
// if the cariage return was a line feed.
$lineEnded = $currentChar === "\n";
if ($currentChar === "\r") {
$lineEnded = true;
$nextChar = $MACRO_STREAM_ADVANCE_CHAR();
if ($nextChar !== "\n") {
$streamIndex--;
}
$currentChar = "\n";
}
if ($lineEnded) {
$MACRO_TOKEN_SET_TYPE('ANNOTATION_NEWLINE');
$MACRO_TOKEN_APPEND_CHAR();
$MACRO_TOKEN_ADVANCE();
$context &= ~$CONTEXT_ASTERISK;
$context &= ~$CONTEXT_CLASS;
if ($MACRO_STREAM_ADVANCE_CHAR() === false) {
goto TOKENIZER_END;
}
goto TOKENIZER_TOP;
}
if ($currentChar === ' ') {
$MACRO_TOKEN_SET_TYPE(($MACRO_HAS_CONTEXT($CONTEXT_ASTERISK)) ? 'ANNOTATION_WHITESPACE' : 'ANNOTATION_WHITESPACE_INDENT');
$MACRO_TOKEN_APPEND_WORD();
$MACRO_TOKEN_ADVANCE();
if ($MACRO_STREAM_ADVANCE_WORD() === false) {
goto TOKENIZER_END;
}
goto TOKENIZER_TOP;
}
if ($MACRO_HAS_CONTEXT($CONTEXT_CONTENT) && $MACRO_HAS_CONTEXT($CONTEXT_ASTERISK)) {
$MACRO_TOKEN_SET_TYPE('ANNOTATION_CONTENT');
$annotationParentCount += substr_count($currentWord, '(');
$annotationParentCount -= substr_count($currentWord, ')');
if ($annotationParentCount === 0) {
$context &= ~$CONTEXT_CONTENT;
$MACRO_TOKEN_SET_TYPE('ANNOTATION_CONTENT_END');
}
$MACRO_TOKEN_APPEND_WORD();
$MACRO_TOKEN_ADVANCE();
if ($MACRO_STREAM_ADVANCE_WORD() === false) {
goto TOKENIZER_END;
}
goto TOKENIZER_TOP;
}
if ($currentChar === '(' && $tokens[$tokenIndex - 1][0] === 'ANNOTATION_CLASS') {
$context |= $CONTEXT_CONTENT;
$annotationParentCount = 1;
$MACRO_TOKEN_SET_TYPE('ANNOTATION_CONTENT_START');
$MACRO_TOKEN_APPEND_CHAR();
$MACRO_TOKEN_ADVANCE();
if ($MACRO_STREAM_ADVANCE_CHAR() === false) {
goto TOKENIZER_END;
}
goto TOKENIZER_TOP;
}
if ($MACRO_HAS_CONTEXT($CONTEXT_DOCBLOCK) && $currentWord === '*/') {
$MACRO_TOKEN_SET_TYPE('ANNOTATION_COMMENTEND');
$MACRO_TOKEN_APPEND_WORD();
$MACRO_TOKEN_ADVANCE();
$context &= ~$CONTEXT_DOCBLOCK;
if ($MACRO_STREAM_ADVANCE_WORD() === false) {
goto TOKENIZER_END;
}
goto TOKENIZER_TOP;
}
if ($currentChar === '*') {
if ($MACRO_HAS_CONTEXT($CONTEXT_DOCBLOCK) && ($MACRO_HAS_CONTEXT($CONTEXT_ASTERISK))) {
$MACRO_TOKEN_SET_TYPE('ANNOTATION_IGNORE');
} else {
$MACRO_TOKEN_SET_TYPE('ANNOTATION_ASTERISK');
$context |= $CONTEXT_ASTERISK;
}
$MACRO_TOKEN_APPEND_CHAR();
$MACRO_TOKEN_ADVANCE();
if ($MACRO_STREAM_ADVANCE_CHAR() === false) {
goto TOKENIZER_END;
}
goto TOKENIZER_TOP;
}
if ($currentChar === '@') {
$MACRO_TOKEN_SET_TYPE('ANNOTATION_CLASS');
$context |= $CONTEXT_CLASS;
$MACRO_TOKEN_APPEND_CHAR();
if ($MACRO_STREAM_ADVANCE_CHAR() === false) {
goto TOKENIZER_END;
}
goto TOKENIZER_TOP;
}
TOKENIZER_CONTINUE:
if ($context && $CONTEXT_CONTENT) {
$MACRO_TOKEN_APPEND_CHAR();
if ($MACRO_STREAM_ADVANCE_CHAR() === false) {
goto TOKENIZER_END;
}
} else {
$MACRO_TOKEN_SET_TYPE('ANNOTATION_IGNORE');
$MACRO_TOKEN_APPEND_LINE();
$MACRO_TOKEN_ADVANCE();
if ($MACRO_STREAM_ADVANCE_LINE() === false) {
goto TOKENIZER_END;
}
}
goto TOKENIZER_TOP;
TOKENIZER_END:
array_pop($tokens);
return $tokens;
}
}

View File

@@ -0,0 +1,160 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Scanner;
use Zend\Code\Annotation\AnnotationManager;
use Zend\Code\Exception;
use Zend\Code\NameInformation;
class CachingFileScanner extends FileScanner
{
/**
* @var array
*/
protected static $cache = array();
/**
* @var null|FileScanner
*/
protected $fileScanner = null;
/**
* @param string $file
* @param AnnotationManager $annotationManager
* @throws Exception\InvalidArgumentException
*/
public function __construct($file, AnnotationManager $annotationManager = null)
{
if (!file_exists($file)) {
throw new Exception\InvalidArgumentException(sprintf(
'File "%s" not found',
$file
));
}
$file = realpath($file);
$cacheId = md5($file) . '/' . ((isset($annotationManager) ? spl_object_hash($annotationManager) : 'no-annotation'));
if (isset(static::$cache[$cacheId])) {
$this->fileScanner = static::$cache[$cacheId];
} else {
$this->fileScanner = new FileScanner($file, $annotationManager);
static::$cache[$cacheId] = $this->fileScanner;
}
}
/**
* @return void
*/
public static function clearCache()
{
static::$cache = array();
}
/**
* @return AnnotationManager
*/
public function getAnnotationManager()
{
return $this->fileScanner->getAnnotationManager();
}
/**
* @return array|null|string
*/
public function getFile()
{
return $this->fileScanner->getFile();
}
/**
* @return null|string
*/
public function getDocComment()
{
return $this->fileScanner->getDocComment();
}
/**
* @return array
*/
public function getNamespaces()
{
return $this->fileScanner->getNamespaces();
}
/**
* @param null|string $namespace
* @return array|null
*/
public function getUses($namespace = null)
{
return $this->fileScanner->getUses($namespace);
}
/**
* @return array
*/
public function getIncludes()
{
return $this->fileScanner->getIncludes();
}
/**
* @return array
*/
public function getClassNames()
{
return $this->fileScanner->getClassNames();
}
/**
* @return array
*/
public function getClasses()
{
return $this->fileScanner->getClasses();
}
/**
* @param int|string $className
* @return ClassScanner
*/
public function getClass($className)
{
return $this->fileScanner->getClass($className);
}
/**
* @param string $className
* @return bool|null|NameInformation
*/
public function getClassNameInformation($className)
{
return $this->fileScanner->getClassNameInformation($className);
}
/**
* @return array
*/
public function getFunctionNames()
{
return $this->fileScanner->getFunctionNames();
}
/**
* @return array
*/
public function getFunctions()
{
return $this->fileScanner->getFunctions();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,236 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Scanner;
use Zend\Code\Annotation;
use Zend\Code\Exception;
use Zend\Code\NameInformation;
class ConstantScanner implements ScannerInterface
{
/**
* @var bool
*/
protected $isScanned = false;
/**
* @var array
*/
protected $tokens;
/**
* @var NameInformation
*/
protected $nameInformation;
/**
* @var string
*/
protected $class;
/**
* @var ClassScanner
*/
protected $scannerClass;
/**
* @var int
*/
protected $lineStart;
/**
* @var string
*/
protected $docComment;
/**
* @var string
*/
protected $name;
/**
* @var string
*/
protected $value;
/**
* Constructor
*
* @param array $constantTokens
* @param NameInformation $nameInformation
*/
public function __construct(array $constantTokens, NameInformation $nameInformation = null)
{
$this->tokens = $constantTokens;
$this->nameInformation = $nameInformation;
}
/**
* @param string $class
*/
public function setClass($class)
{
$this->class = $class;
}
/**
* @param ClassScanner $scannerClass
*/
public function setScannerClass(ClassScanner $scannerClass)
{
$this->scannerClass = $scannerClass;
}
/**
* @return ClassScanner
*/
public function getClassScanner()
{
return $this->scannerClass;
}
/**
* @return string
*/
public function getName()
{
$this->scan();
return $this->name;
}
/**
* @return string
*/
public function getValue()
{
$this->scan();
return $this->value;
}
/**
* @return string
*/
public function getDocComment()
{
$this->scan();
return $this->docComment;
}
/**
* @param Annotation\AnnotationManager $annotationManager
* @return AnnotationScanner
*/
public function getAnnotations(Annotation\AnnotationManager $annotationManager)
{
if (($docComment = $this->getDocComment()) == '') {
return false;
}
return new AnnotationScanner($annotationManager, $docComment, $this->nameInformation);
}
/**
* @return string
*/
public function __toString()
{
$this->scan();
return var_export($this, true);
}
/**
* Scan tokens
*
* @throws Exception\RuntimeException
*/
protected function scan()
{
if ($this->isScanned) {
return;
}
if (!$this->tokens) {
throw new Exception\RuntimeException('No tokens were provided');
}
/**
* Variables & Setup
*/
$tokens = &$this->tokens;
reset($tokens);
SCANNER_TOP:
$token = current($tokens);
if (!is_string($token)) {
list($tokenType, $tokenContent, $tokenLine) = $token;
switch ($tokenType) {
case T_DOC_COMMENT:
if ($this->docComment === null && $this->name === null) {
$this->docComment = $tokenContent;
}
goto SCANNER_CONTINUE;
// fall-through
case T_STRING:
$string = (is_string($token)) ? $token : $tokenContent;
if (null === $this->name) {
$this->name = $string;
} else {
if ('self' == strtolower($string)) {
list($tokenNextType, $tokenNextContent, $tokenNextLine) = next($tokens);
if ('::' == $tokenNextContent) {
list($tokenNextType, $tokenNextContent, $tokenNextLine) = next($tokens);
if ($this->getClassScanner()->getConstant($tokenNextContent)) {
$this->value = $this->getClassScanner()->getConstant($tokenNextContent)->getValue();
}
}
}
}
goto SCANNER_CONTINUE;
// fall-through
case T_CONSTANT_ENCAPSED_STRING:
case T_DNUMBER:
case T_LNUMBER:
$string = (is_string($token)) ? $token : $tokenContent;
if (substr($string, 0, 1) === '"' || substr($string, 0, 1) === "'") {
$this->value = substr($string, 1, -1); // Remove quotes
} else {
$this->value = $string;
}
goto SCANNER_CONTINUE;
// fall-trough
default:
goto SCANNER_CONTINUE;
}
}
SCANNER_CONTINUE:
if (next($this->tokens) === false) {
goto SCANNER_END;
}
goto SCANNER_TOP;
SCANNER_END:
$this->isScanned = true;
}
}

View File

@@ -0,0 +1,381 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Scanner;
use Zend\Code\Exception;
class DerivedClassScanner extends ClassScanner
{
/**
* @var DirectoryScanner
*/
protected $directoryScanner = null;
/**
* @var ClassScanner
*/
protected $classScanner = null;
/**
* @var array
*/
protected $parentClassScanners = array();
/**
* @var array
*/
protected $interfaceClassScanners = array();
/**
* @param ClassScanner $classScanner
* @param DirectoryScanner $directoryScanner
*/
public function __construct(ClassScanner $classScanner, DirectoryScanner $directoryScanner)
{
$this->classScanner = $classScanner;
$this->directoryScanner = $directoryScanner;
$currentScannerClass = $classScanner;
while ($currentScannerClass && $currentScannerClass->hasParentClass()) {
$currentParentClassName = $currentScannerClass->getParentClass();
if ($directoryScanner->hasClass($currentParentClassName)) {
$currentParentClass = $directoryScanner->getClass($currentParentClassName);
$this->parentClassScanners[$currentParentClassName] = $currentParentClass;
$currentScannerClass = $currentParentClass;
} else {
$currentScannerClass = false;
}
}
foreach ($interfaces = $this->classScanner->getInterfaces() as $iName) {
if ($directoryScanner->hasClass($iName)) {
$this->interfaceClassScanners[$iName] = $directoryScanner->getClass($iName);
}
}
}
/**
* @return null|string
*/
public function getName()
{
return $this->classScanner->getName();
}
/**
* @return null|string
*/
public function getShortName()
{
return $this->classScanner->getShortName();
}
/**
* @return bool
*/
public function isInstantiable()
{
return $this->classScanner->isInstantiable();
}
/**
* @return bool
*/
public function isFinal()
{
return $this->classScanner->isFinal();
}
/**
* @return bool
*/
public function isAbstract()
{
return $this->classScanner->isAbstract();
}
/**
* @return bool
*/
public function isInterface()
{
return $this->classScanner->isInterface();
}
/**
* @return array
*/
public function getParentClasses()
{
return array_keys($this->parentClassScanners);
}
/**
* @return bool
*/
public function hasParentClass()
{
return ($this->classScanner->getParentClass() !== null);
}
/**
* @return null|string
*/
public function getParentClass()
{
return $this->classScanner->getParentClass();
}
/**
* @param bool $returnClassScanners
* @return array
*/
public function getInterfaces($returnClassScanners = false)
{
if ($returnClassScanners) {
return $this->interfaceClassScanners;
}
$interfaces = $this->classScanner->getInterfaces();
foreach ($this->parentClassScanners as $pClassScanner) {
$interfaces = array_merge($interfaces, $pClassScanner->getInterfaces());
}
return $interfaces;
}
/**
* Return a list of constant names
*
* @return array
*/
public function getConstantNames()
{
$constants = $this->classScanner->getConstantNames();
foreach ($this->parentClassScanners as $pClassScanner) {
$constants = array_merge($constants, $pClassScanner->getConstantNames());
}
return $constants;
}
/**
* Return a list of constants
*
* @param bool $namesOnly Set false to return instances of ConstantScanner
* @return array|ConstantScanner[]
*/
public function getConstants($namesOnly = true)
{
if (true === $namesOnly) {
trigger_error('Use method getConstantNames() instead', E_USER_DEPRECATED);
return $this->getConstantNames();
}
$constants = $this->classScanner->getConstants();
foreach ($this->parentClassScanners as $pClassScanner) {
$constants = array_merge($constants, $pClassScanner->getConstants($namesOnly));
}
return $constants;
}
/**
* Return a single constant by given name or index of info
*
* @param string|int $constantNameOrInfoIndex
* @throws Exception\InvalidArgumentException
* @return bool|ConstantScanner
*/
public function getConstant($constantNameOrInfoIndex)
{
if ($this->classScanner->hasConstant($constantNameOrInfoIndex)) {
return $this->classScanner->getConstant($constantNameOrInfoIndex);
}
foreach ($this->parentClassScanners as $pClassScanner) {
if ($pClassScanner->hasConstant($constantNameOrInfoIndex)) {
return $pClassScanner->getConstant($constantNameOrInfoIndex);
}
}
throw new Exception\InvalidArgumentException(sprintf(
'Constant %s not found in %s',
$constantNameOrInfoIndex,
$this->classScanner->getName()
));
}
/**
* Verify if class or parent class has constant
*
* @param string $name
* @return bool
*/
public function hasConstant($name)
{
if ($this->classScanner->hasConstant($name)) {
return true;
}
foreach ($this->parentClassScanners as $pClassScanner) {
if ($pClassScanner->hasConstant($name)) {
return true;
}
}
return false;
}
/**
* Return a list of property names
*
* @return array
*/
public function getPropertyNames()
{
$properties = $this->classScanner->getPropertyNames();
foreach ($this->parentClassScanners as $pClassScanner) {
$properties = array_merge($properties, $pClassScanner->getPropertyNames());
}
return $properties;
}
/**
* @param bool $returnScannerProperty
* @return array
*/
public function getProperties($returnScannerProperty = false)
{
$properties = $this->classScanner->getProperties($returnScannerProperty);
foreach ($this->parentClassScanners as $pClassScanner) {
$properties = array_merge($properties, $pClassScanner->getProperties($returnScannerProperty));
}
return $properties;
}
/**
* Return a single property by given name or index of info
*
* @param string|int $propertyNameOrInfoIndex
* @throws Exception\InvalidArgumentException
* @return bool|PropertyScanner
*/
public function getProperty($propertyNameOrInfoIndex)
{
if ($this->classScanner->hasProperty($propertyNameOrInfoIndex)) {
return $this->classScanner->getProperty($propertyNameOrInfoIndex);
}
foreach ($this->parentClassScanners as $pClassScanner) {
if ($pClassScanner->hasProperty($propertyNameOrInfoIndex)) {
return $pClassScanner->getProperty($propertyNameOrInfoIndex);
}
}
throw new Exception\InvalidArgumentException(sprintf(
'Property %s not found in %s',
$propertyNameOrInfoIndex,
$this->classScanner->getName()
));
}
/**
* Verify if class or parent class has property
*
* @param string $name
* @return bool
*/
public function hasProperty($name)
{
if ($this->classScanner->hasProperty($name)) {
return true;
}
foreach ($this->parentClassScanners as $pClassScanner) {
if ($pClassScanner->hasProperty($name)) {
return true;
}
}
return false;
}
/**
* @return array
*/
public function getMethodNames()
{
$methods = $this->classScanner->getMethodNames();
foreach ($this->parentClassScanners as $pClassScanner) {
$methods = array_merge($methods, $pClassScanner->getMethodNames());
}
return $methods;
}
/**
* @return MethodScanner[]
*/
public function getMethods()
{
$methods = $this->classScanner->getMethods();
foreach ($this->parentClassScanners as $pClassScanner) {
$methods = array_merge($methods, $pClassScanner->getMethods());
}
return $methods;
}
/**
* @param int|string $methodNameOrInfoIndex
* @return MethodScanner
* @throws Exception\InvalidArgumentException
*/
public function getMethod($methodNameOrInfoIndex)
{
if ($this->classScanner->hasMethod($methodNameOrInfoIndex)) {
return $this->classScanner->getMethod($methodNameOrInfoIndex);
}
foreach ($this->parentClassScanners as $pClassScanner) {
if ($pClassScanner->hasMethod($methodNameOrInfoIndex)) {
return $pClassScanner->getMethod($methodNameOrInfoIndex);
}
}
throw new Exception\InvalidArgumentException(sprintf(
'Method %s not found in %s',
$methodNameOrInfoIndex,
$this->classScanner->getName()
));
}
/**
* Verify if class or parent class has method by given name
*
* @param string $name
* @return bool
*/
public function hasMethod($name)
{
if ($this->classScanner->hasMethod($name)) {
return true;
}
foreach ($this->parentClassScanners as $pClassScanner) {
if ($pClassScanner->hasMethod($name)) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,272 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Scanner;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use Zend\Code\Exception;
class DirectoryScanner implements ScannerInterface
{
/**
* @var bool
*/
protected $isScanned = false;
/**
* @var string[]|DirectoryScanner[]
*/
protected $directories = array();
/**
* @var FileScanner[]
*/
protected $fileScanners = array();
/**
* @var array
*/
protected $classToFileScanner = null;
/**
* @param null|string|array $directory
*/
public function __construct($directory = null)
{
if ($directory) {
if (is_string($directory)) {
$this->addDirectory($directory);
} elseif (is_array($directory)) {
foreach ($directory as $d) {
$this->addDirectory($d);
}
}
}
}
/**
* @param DirectoryScanner|string $directory
* @return void
* @throws Exception\InvalidArgumentException
*/
public function addDirectory($directory)
{
if ($directory instanceof DirectoryScanner) {
$this->directories[] = $directory;
} elseif (is_string($directory)) {
$realDir = realpath($directory);
if (!$realDir || !is_dir($realDir)) {
throw new Exception\InvalidArgumentException(sprintf(
'Directory "%s" does not exist',
$realDir
));
}
$this->directories[] = $realDir;
} else {
throw new Exception\InvalidArgumentException(
'The argument provided was neither a DirectoryScanner or directory path'
);
}
}
/**
* @param DirectoryScanner $directoryScanner
* @return void
*/
public function addDirectoryScanner(DirectoryScanner $directoryScanner)
{
$this->addDirectory($directoryScanner);
}
/**
* @param FileScanner $fileScanner
* @return void
*/
public function addFileScanner(FileScanner $fileScanner)
{
$this->fileScanners[] = $fileScanner;
}
/**
* @return void
*/
protected function scan()
{
if ($this->isScanned) {
return;
}
// iterate directories creating file scanners
foreach ($this->directories as $directory) {
if ($directory instanceof DirectoryScanner) {
$directory->scan();
if ($directory->fileScanners) {
$this->fileScanners = array_merge($this->fileScanners, $directory->fileScanners);
}
} else {
$rdi = new RecursiveDirectoryIterator($directory);
foreach (new RecursiveIteratorIterator($rdi) as $item) {
if ($item->isFile() && pathinfo($item->getRealPath(), PATHINFO_EXTENSION) == 'php') {
$this->fileScanners[] = new FileScanner($item->getRealPath());
}
}
}
}
$this->isScanned = true;
}
/**
* @todo implement method
*/
public function getNamespaces()
{
// @todo
}
/**
* @param bool $returnFileScanners
* @return array
*/
public function getFiles($returnFileScanners = false)
{
$this->scan();
$return = array();
foreach ($this->fileScanners as $fileScanner) {
$return[] = ($returnFileScanners) ? $fileScanner : $fileScanner->getFile();
}
return $return;
}
/**
* @return array
*/
public function getClassNames()
{
$this->scan();
if ($this->classToFileScanner === null) {
$this->createClassToFileScannerCache();
}
return array_keys($this->classToFileScanner);
}
/**
* @param bool $returnDerivedScannerClass
* @return array
*/
public function getClasses($returnDerivedScannerClass = false)
{
$this->scan();
if ($this->classToFileScanner === null) {
$this->createClassToFileScannerCache();
}
$returnClasses = array();
foreach ($this->classToFileScanner as $className => $fsIndex) {
$classScanner = $this->fileScanners[$fsIndex]->getClass($className);
if ($returnDerivedScannerClass) {
$classScanner = new DerivedClassScanner($classScanner, $this);
}
$returnClasses[] = $classScanner;
}
return $returnClasses;
}
/**
* @param string $class
* @return bool
*/
public function hasClass($class)
{
$this->scan();
if ($this->classToFileScanner === null) {
$this->createClassToFileScannerCache();
}
return (isset($this->classToFileScanner[$class]));
}
/**
* @param string $class
* @param bool $returnDerivedScannerClass
* @return ClassScanner|DerivedClassScanner
* @throws Exception\InvalidArgumentException
*/
public function getClass($class, $returnDerivedScannerClass = false)
{
$this->scan();
if ($this->classToFileScanner === null) {
$this->createClassToFileScannerCache();
}
if (!isset($this->classToFileScanner[$class])) {
throw new Exception\InvalidArgumentException('Class not found.');
}
/** @var FileScanner $fs */
$fs = $this->fileScanners[$this->classToFileScanner[$class]];
$returnClass = $fs->getClass($class);
if (($returnClass instanceof ClassScanner) && $returnDerivedScannerClass) {
return new DerivedClassScanner($returnClass, $this);
}
return $returnClass;
}
/**
* Create class to file scanner cache
*
* @return void
*/
protected function createClassToFileScannerCache()
{
if ($this->classToFileScanner !== null) {
return;
}
$this->classToFileScanner = array();
/** @var FileScanner $fileScanner */
foreach ($this->fileScanners as $fsIndex => $fileScanner) {
$fsClasses = $fileScanner->getClassNames();
foreach ($fsClasses as $fsClassName) {
$this->classToFileScanner[$fsClassName] = $fsIndex;
}
}
}
/**
* Export
*
* @todo implement method
*/
public static function export()
{
// @todo
}
/**
* __ToString
*
* @todo implement method
*/
public function __toString()
{
// @todo
}
}

View File

@@ -0,0 +1,326 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Scanner;
use Zend\Code\Annotation\AnnotationManager;
use Zend\Code\NameInformation;
class DocBlockScanner implements ScannerInterface
{
/**
* @var bool
*/
protected $isScanned = false;
/**
* @var string
*/
protected $docComment = null;
/**
* @var NameInformation
*/
protected $nameInformation = null;
/**
* @var AnnotationManager
*/
protected $annotationManager = null;
/**
* @var string
*/
protected $shortDescription = null;
/**
* @var string
*/
protected $longDescription = '';
/**
* @var array
*/
protected $tags = array();
/**
* @var array
*/
protected $annotations = array();
/**
* @param string $docComment
* @param null|NameInformation $nameInformation
*/
public function __construct($docComment, NameInformation $nameInformation = null)
{
$this->docComment = $docComment;
$this->nameInformation = $nameInformation;
}
/**
* @return string
*/
public function getShortDescription()
{
$this->scan();
return $this->shortDescription;
}
/**
* @return string
*/
public function getLongDescription()
{
$this->scan();
return $this->longDescription;
}
/**
* @return array
*/
public function getTags()
{
$this->scan();
return $this->tags;
}
/**
* @return array
*/
public function getAnnotations()
{
$this->scan();
return $this->annotations;
}
/**
* @return void
*/
protected function scan()
{
if ($this->isScanned) {
return;
}
$mode = 1;
$tokens = $this->tokenize();
$tagIndex = null;
reset($tokens);
SCANNER_TOP:
$token = current($tokens);
switch ($token[0]) {
case 'DOCBLOCK_NEWLINE':
if ($this->shortDescription != '' && $tagIndex === null) {
$mode = 2;
} else {
$this->longDescription .= $token[1];
}
goto SCANNER_CONTINUE;
//goto no break needed
case 'DOCBLOCK_WHITESPACE':
case 'DOCBLOCK_TEXT':
if ($tagIndex !== null) {
$this->tags[$tagIndex]['value'] .= ($this->tags[$tagIndex]['value'] == '') ? $token[1] : ' ' . $token[1];
goto SCANNER_CONTINUE;
} elseif ($mode <= 2) {
if ($mode == 1) {
$this->shortDescription .= $token[1];
} else {
$this->longDescription .= $token[1];
}
goto SCANNER_CONTINUE;
}
//gotos no break needed
case 'DOCBLOCK_TAG':
array_push($this->tags, array('name' => $token[1],
'value' => ''));
end($this->tags);
$tagIndex = key($this->tags);
$mode = 3;
goto SCANNER_CONTINUE;
//goto no break needed
case 'DOCBLOCK_COMMENTEND':
goto SCANNER_END;
}
SCANNER_CONTINUE:
if (next($tokens) === false) {
goto SCANNER_END;
}
goto SCANNER_TOP;
SCANNER_END:
$this->shortDescription = trim($this->shortDescription);
$this->longDescription = trim($this->longDescription);
$this->isScanned = true;
}
/**
* @return array
*/
protected function tokenize()
{
static $CONTEXT_INSIDE_DOCBLOCK = 0x01;
static $CONTEXT_INSIDE_ASTERISK = 0x02;
$context = 0x00;
$stream = $this->docComment;
$streamIndex = null;
$tokens = array();
$tokenIndex = null;
$currentChar = null;
$currentWord = null;
$currentLine = null;
$MACRO_STREAM_ADVANCE_CHAR = function ($positionsForward = 1) use (&$stream, &$streamIndex, &$currentChar, &$currentWord, &$currentLine) {
$positionsForward = ($positionsForward > 0) ? $positionsForward : 1;
$streamIndex = ($streamIndex === null) ? 0 : $streamIndex + $positionsForward;
if (!isset($stream[$streamIndex])) {
$currentChar = false;
return false;
}
$currentChar = $stream[$streamIndex];
$matches = array();
$currentLine = (preg_match('#(.*?)\r?\n#', $stream, $matches, null, $streamIndex) === 1) ? $matches[1] : substr($stream, $streamIndex);
if ($currentChar === ' ') {
$currentWord = (preg_match('#( +)#', $currentLine, $matches) === 1) ? $matches[1] : $currentLine;
} else {
$currentWord = (($matches = strpos($currentLine, ' ')) !== false) ? substr($currentLine, 0, $matches) : $currentLine;
}
return $currentChar;
};
$MACRO_STREAM_ADVANCE_WORD = function () use (&$currentWord, &$MACRO_STREAM_ADVANCE_CHAR) {
return $MACRO_STREAM_ADVANCE_CHAR(strlen($currentWord));
};
$MACRO_STREAM_ADVANCE_LINE = function () use (&$currentLine, &$MACRO_STREAM_ADVANCE_CHAR) {
return $MACRO_STREAM_ADVANCE_CHAR(strlen($currentLine));
};
$MACRO_TOKEN_ADVANCE = function () use (&$tokenIndex, &$tokens) {
$tokenIndex = ($tokenIndex === null) ? 0 : $tokenIndex + 1;
$tokens[$tokenIndex] = array('DOCBLOCK_UNKNOWN', '');
};
$MACRO_TOKEN_SET_TYPE = function ($type) use (&$tokenIndex, &$tokens) {
$tokens[$tokenIndex][0] = $type;
};
$MACRO_TOKEN_APPEND_CHAR = function () use (&$currentChar, &$tokens, &$tokenIndex) {
$tokens[$tokenIndex][1] .= $currentChar;
};
$MACRO_TOKEN_APPEND_WORD = function () use (&$currentWord, &$tokens, &$tokenIndex) {
$tokens[$tokenIndex][1] .= $currentWord;
};
$MACRO_TOKEN_APPEND_WORD_PARTIAL = function ($length) use (&$currentWord, &$tokens, &$tokenIndex) {
$tokens[$tokenIndex][1] .= substr($currentWord, 0, $length);
};
$MACRO_TOKEN_APPEND_LINE = function () use (&$currentLine, &$tokens, &$tokenIndex) {
$tokens[$tokenIndex][1] .= $currentLine;
};
$MACRO_STREAM_ADVANCE_CHAR();
$MACRO_TOKEN_ADVANCE();
TOKENIZER_TOP:
if ($context === 0x00 && $currentChar === '/' && $currentWord === '/**') {
$MACRO_TOKEN_SET_TYPE('DOCBLOCK_COMMENTSTART');
$MACRO_TOKEN_APPEND_WORD();
$MACRO_TOKEN_ADVANCE();
$context |= $CONTEXT_INSIDE_DOCBLOCK;
$context |= $CONTEXT_INSIDE_ASTERISK;
if ($MACRO_STREAM_ADVANCE_WORD() === false) {
goto TOKENIZER_END;
}
goto TOKENIZER_TOP;
}
if ($context & $CONTEXT_INSIDE_DOCBLOCK && $currentWord === '*/') {
$MACRO_TOKEN_SET_TYPE('DOCBLOCK_COMMENTEND');
$MACRO_TOKEN_APPEND_WORD();
$MACRO_TOKEN_ADVANCE();
$context &= ~$CONTEXT_INSIDE_DOCBLOCK;
if ($MACRO_STREAM_ADVANCE_WORD() === false) {
goto TOKENIZER_END;
}
goto TOKENIZER_TOP;
}
if ($currentChar === ' ' || $currentChar === "\t") {
$MACRO_TOKEN_SET_TYPE(($context & $CONTEXT_INSIDE_ASTERISK) ? 'DOCBLOCK_WHITESPACE' : 'DOCBLOCK_WHITESPACE_INDENT');
$MACRO_TOKEN_APPEND_WORD();
$MACRO_TOKEN_ADVANCE();
if ($MACRO_STREAM_ADVANCE_WORD() === false) {
goto TOKENIZER_END;
}
goto TOKENIZER_TOP;
}
if ($currentChar === '*') {
if (($context & $CONTEXT_INSIDE_DOCBLOCK) && ($context & $CONTEXT_INSIDE_ASTERISK)) {
$MACRO_TOKEN_SET_TYPE('DOCBLOCK_TEXT');
} else {
$MACRO_TOKEN_SET_TYPE('DOCBLOCK_ASTERISK');
$context |= $CONTEXT_INSIDE_ASTERISK;
}
$MACRO_TOKEN_APPEND_CHAR();
$MACRO_TOKEN_ADVANCE();
if ($MACRO_STREAM_ADVANCE_CHAR() === false) {
goto TOKENIZER_END;
}
goto TOKENIZER_TOP;
}
if ($currentChar === '@') {
$MACRO_TOKEN_SET_TYPE('DOCBLOCK_TAG');
$MACRO_TOKEN_APPEND_WORD();
$MACRO_TOKEN_ADVANCE();
if ($MACRO_STREAM_ADVANCE_WORD() === false) {
goto TOKENIZER_END;
}
goto TOKENIZER_TOP;
}
if ($currentChar === "\n") {
$MACRO_TOKEN_SET_TYPE('DOCBLOCK_NEWLINE');
$MACRO_TOKEN_APPEND_CHAR();
$MACRO_TOKEN_ADVANCE();
$context &= ~$CONTEXT_INSIDE_ASTERISK;
if ($MACRO_STREAM_ADVANCE_CHAR() === false) {
goto TOKENIZER_END;
}
goto TOKENIZER_TOP;
}
$MACRO_TOKEN_SET_TYPE('DOCBLOCK_TEXT');
$MACRO_TOKEN_APPEND_LINE();
$MACRO_TOKEN_ADVANCE();
if ($MACRO_STREAM_ADVANCE_LINE() === false) {
goto TOKENIZER_END;
}
goto TOKENIZER_TOP;
TOKENIZER_END:
array_pop($tokens);
return $tokens;
}
}

View File

@@ -0,0 +1,46 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Scanner;
use Zend\Code\Annotation\AnnotationManager;
use Zend\Code\Exception;
class FileScanner extends TokenArrayScanner implements ScannerInterface
{
/**
* @var string
*/
protected $file = null;
/**
* @param string $file
* @param null|AnnotationManager $annotationManager
* @throws Exception\InvalidArgumentException
*/
public function __construct($file, AnnotationManager $annotationManager = null)
{
$this->file = $file;
if (!file_exists($file)) {
throw new Exception\InvalidArgumentException(sprintf(
'File "%s" not found',
$file
));
}
parent::__construct(token_get_all(file_get_contents($file)), $annotationManager);
}
/**
* @return string
*/
public function getFile()
{
return $this->file;
}
}

View File

@@ -0,0 +1,16 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Scanner;
class FunctionScanner
{
// @todo
// Should this extend something similar to MethodScanner? Similar to ReflectionFunctionAbstract
}

View File

@@ -0,0 +1,607 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Scanner;
use Zend\Code\Annotation\AnnotationManager;
use Zend\Code\Exception;
use Zend\Code\NameInformation;
class MethodScanner implements ScannerInterface
{
/**
* @var bool
*/
protected $isScanned = false;
/**
* @var string
*/
protected $docComment = null;
/**
* @var ClassScanner
*/
protected $scannerClass = null;
/**
* @var string
*/
protected $class = null;
/**
* @var string
*/
protected $name = null;
/**
* @var int
*/
protected $lineStart = null;
/**
* @var int
*/
protected $lineEnd = null;
/**
* @var bool
*/
protected $isFinal = false;
/**
* @var bool
*/
protected $isAbstract = false;
/**
* @var bool
*/
protected $isPublic = true;
/**
* @var bool
*/
protected $isProtected = false;
/**
* @var bool
*/
protected $isPrivate = false;
/**
* @var bool
*/
protected $isStatic = false;
/**
* @var string
*/
protected $body = '';
/**
* @var array
*/
protected $tokens = array();
/**
* @var NameInformation
*/
protected $nameInformation = null;
/**
* @var array
*/
protected $infos = array();
/**
* @param array $methodTokens
* @param NameInformation $nameInformation
*/
public function __construct(array $methodTokens, NameInformation $nameInformation = null)
{
$this->tokens = $methodTokens;
$this->nameInformation = $nameInformation;
}
/**
* @param string $class
* @return MethodScanner
*/
public function setClass($class)
{
$this->class = (string) $class;
return $this;
}
/**
* @param ClassScanner $scannerClass
* @return MethodScanner
*/
public function setScannerClass(ClassScanner $scannerClass)
{
$this->scannerClass = $scannerClass;
return $this;
}
/**
* @return MethodScanner
*/
public function getClassScanner()
{
return $this->scannerClass;
}
/**
* @return string
*/
public function getName()
{
$this->scan();
return $this->name;
}
/**
* @return int
*/
public function getLineStart()
{
$this->scan();
return $this->lineStart;
}
/**
* @return int
*/
public function getLineEnd()
{
$this->scan();
return $this->lineEnd;
}
/**
* @return string
*/
public function getDocComment()
{
$this->scan();
return $this->docComment;
}
/**
* @param AnnotationManager $annotationManager
* @return AnnotationScanner
*/
public function getAnnotations(AnnotationManager $annotationManager)
{
if (($docComment = $this->getDocComment()) == '') {
return false;
}
return new AnnotationScanner($annotationManager, $docComment, $this->nameInformation);
}
/**
* @return bool
*/
public function isFinal()
{
$this->scan();
return $this->isFinal;
}
/**
* @return bool
*/
public function isAbstract()
{
$this->scan();
return $this->isAbstract;
}
/**
* @return bool
*/
public function isPublic()
{
$this->scan();
return $this->isPublic;
}
/**
* @return bool
*/
public function isProtected()
{
$this->scan();
return $this->isProtected;
}
/**
* @return bool
*/
public function isPrivate()
{
$this->scan();
return $this->isPrivate;
}
/**
* @return bool
*/
public function isStatic()
{
$this->scan();
return $this->isStatic;
}
/**
* Override the given name for a method, this is necessary to
* support traits.
*
* @param $name
* @return self
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Visibility must be of T_PUBLIC, T_PRIVATE or T_PROTECTED
* Needed to support traits
*
* @param $visibility T_PUBLIC | T_PRIVATE | T_PROTECTED
* @return self
* @throws \Zend\Code\Exception
*/
public function setVisibility($visibility)
{
switch (strtolower($visibility)) {
case T_PUBLIC:
$this->isPublic = true;
$this->isPrivate = false;
$this->isProtected = false;
break;
case T_PRIVATE:
$this->isPublic = false;
$this->isPrivate = true;
$this->isProtected = false;
break;
case T_PROTECTED:
$this->isPublic = false;
$this->isPrivate = false;
$this->isProtected = true;
break;
default:
throw new Exception("Invalid visibility argument passed to setVisibility.");
}
return $this;
}
/**
* @return int
*/
public function getNumberOfParameters()
{
return count($this->getParameters());
}
/**
* @param bool $returnScanner
* @return array
*/
public function getParameters($returnScanner = false)
{
$this->scan();
$return = array();
foreach ($this->infos as $info) {
if ($info['type'] != 'parameter') {
continue;
}
if (!$returnScanner) {
$return[] = $info['name'];
} else {
$return[] = $this->getParameter($info['name']);
}
}
return $return;
}
/**
* @param int|string $parameterNameOrInfoIndex
* @return ParameterScanner
* @throws Exception\InvalidArgumentException
*/
public function getParameter($parameterNameOrInfoIndex)
{
$this->scan();
if (is_int($parameterNameOrInfoIndex)) {
$info = $this->infos[$parameterNameOrInfoIndex];
if ($info['type'] != 'parameter') {
throw new Exception\InvalidArgumentException('Index of info offset is not about a parameter');
}
} elseif (is_string($parameterNameOrInfoIndex)) {
foreach ($this->infos as $info) {
if ($info['type'] === 'parameter' && $info['name'] === $parameterNameOrInfoIndex) {
break;
}
unset($info);
}
if (!isset($info)) {
throw new Exception\InvalidArgumentException('Index of info offset is not about a parameter');
}
}
$p = new ParameterScanner(
array_slice($this->tokens, $info['tokenStart'], $info['tokenEnd'] - $info['tokenStart']),
$this->nameInformation
);
$p->setDeclaringFunction($this->name);
$p->setDeclaringScannerFunction($this);
$p->setDeclaringClass($this->class);
$p->setDeclaringScannerClass($this->scannerClass);
$p->setPosition($info['position']);
return $p;
}
/**
* @return string
*/
public function getBody()
{
$this->scan();
return $this->body;
}
public static function export()
{
// @todo
}
public function __toString()
{
$this->scan();
return var_export($this, true);
}
protected function scan()
{
if ($this->isScanned) {
return;
}
if (!$this->tokens) {
throw new Exception\RuntimeException('No tokens were provided');
}
/**
* Variables & Setup
*/
$tokens = &$this->tokens; // localize
$infos = &$this->infos; // localize
$tokenIndex = null;
$token = null;
$tokenType = null;
$tokenContent = null;
$tokenLine = null;
$infoIndex = 0;
$parentCount = 0;
/*
* MACRO creation
*/
$MACRO_TOKEN_ADVANCE = function () use (
&$tokens,
&$tokenIndex,
&$token,
&$tokenType,
&$tokenContent,
&$tokenLine
) {
static $lastTokenArray = null;
$tokenIndex = ($tokenIndex === null) ? 0 : $tokenIndex + 1;
if (!isset($tokens[$tokenIndex])) {
$token = false;
$tokenContent = false;
$tokenType = false;
$tokenLine = false;
return false;
}
$token = $tokens[$tokenIndex];
if (is_string($token)) {
$tokenType = null;
$tokenContent = $token;
$tokenLine = $tokenLine + substr_count(
$lastTokenArray[1],
"\n"
); // adjust token line by last known newline count
} else {
list($tokenType, $tokenContent, $tokenLine) = $token;
}
return $tokenIndex;
};
$MACRO_INFO_START = function () use (&$infoIndex, &$infos, &$tokenIndex, &$tokenLine) {
$infos[$infoIndex] = array(
'type' => 'parameter',
'tokenStart' => $tokenIndex,
'tokenEnd' => null,
'lineStart' => $tokenLine,
'lineEnd' => $tokenLine,
'name' => null,
'position' => $infoIndex + 1, // position is +1 of infoIndex
);
};
$MACRO_INFO_ADVANCE = function () use (&$infoIndex, &$infos, &$tokenIndex, &$tokenLine) {
$infos[$infoIndex]['tokenEnd'] = $tokenIndex;
$infos[$infoIndex]['lineEnd'] = $tokenLine;
$infoIndex++;
return $infoIndex;
};
/**
* START FINITE STATE MACHINE FOR SCANNING TOKENS
*/
// Initialize token
$MACRO_TOKEN_ADVANCE();
SCANNER_TOP:
$this->lineStart = ($this->lineStart) ? : $tokenLine;
switch ($tokenType) {
case T_DOC_COMMENT:
$this->lineStart = null;
if ($this->docComment === null && $this->name === null) {
$this->docComment = $tokenContent;
}
goto SCANNER_CONTINUE_SIGNATURE;
//goto (no break needed);
case T_FINAL:
$this->isFinal = true;
goto SCANNER_CONTINUE_SIGNATURE;
//goto (no break needed);
case T_ABSTRACT:
$this->isAbstract = true;
goto SCANNER_CONTINUE_SIGNATURE;
//goto (no break needed);
case T_PUBLIC:
// use defaults
goto SCANNER_CONTINUE_SIGNATURE;
//goto (no break needed);
case T_PROTECTED:
$this->setVisibility(T_PROTECTED);
goto SCANNER_CONTINUE_SIGNATURE;
//goto (no break needed);
case T_PRIVATE:
$this->setVisibility(T_PRIVATE);
goto SCANNER_CONTINUE_SIGNATURE;
//goto (no break needed);
case T_STATIC:
$this->isStatic = true;
goto SCANNER_CONTINUE_SIGNATURE;
//goto (no break needed);
case T_VARIABLE:
case T_STRING:
if ($tokenType === T_STRING && $parentCount === 0) {
$this->name = $tokenContent;
}
if ($parentCount === 1) {
if (!isset($infos[$infoIndex])) {
$MACRO_INFO_START();
}
if ($tokenType === T_VARIABLE) {
$infos[$infoIndex]['name'] = ltrim($tokenContent, '$');
}
}
goto SCANNER_CONTINUE_SIGNATURE;
//goto (no break needed);
case null:
switch ($tokenContent) {
case '&':
if (!isset($infos[$infoIndex])) {
$MACRO_INFO_START();
}
goto SCANNER_CONTINUE_SIGNATURE;
//goto (no break needed);
case '(':
$parentCount++;
goto SCANNER_CONTINUE_SIGNATURE;
//goto (no break needed);
case ')':
$parentCount--;
if ($parentCount > 0) {
goto SCANNER_CONTINUE_SIGNATURE;
}
if ($parentCount === 0) {
if ($infos) {
$MACRO_INFO_ADVANCE();
}
$context = 'body';
}
goto SCANNER_CONTINUE_BODY;
//goto (no break needed);
case ',':
if ($parentCount === 1) {
$MACRO_INFO_ADVANCE();
}
goto SCANNER_CONTINUE_SIGNATURE;
}
}
SCANNER_CONTINUE_SIGNATURE:
if ($MACRO_TOKEN_ADVANCE() === false) {
goto SCANNER_END;
}
goto SCANNER_TOP;
SCANNER_CONTINUE_BODY:
$braceCount = 0;
while ($MACRO_TOKEN_ADVANCE() !== false) {
if ($tokenContent == '}') {
$braceCount--;
}
if ($braceCount > 0) {
$this->body .= $tokenContent;
}
if ($tokenContent == '{') {
$braceCount++;
}
$this->lineEnd = $tokenLine;
}
SCANNER_END:
$this->isScanned = true;
return;
}
}

View File

@@ -0,0 +1,352 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Scanner;
use Zend\Code\NameInformation;
class ParameterScanner
{
/**
* @var bool
*/
protected $isScanned = false;
/**
* @var null|ClassScanner
*/
protected $declaringScannerClass = null;
/**
* @var null|string
*/
protected $declaringClass = null;
/**
* @var null|MethodScanner
*/
protected $declaringScannerFunction = null;
/**
* @var null|string
*/
protected $declaringFunction = null;
/**
* @var null|string
*/
protected $defaultValue = null;
/**
* @var null|string
*/
protected $class = null;
/**
* @var null|string
*/
protected $name = null;
/**
* @var null|int
*/
protected $position = null;
/**
* @var bool
*/
protected $isArray = false;
/**
* @var bool
*/
protected $isDefaultValueAvailable = false;
/**
* @var bool
*/
protected $isOptional = false;
/**
* @var bool
*/
protected $isPassedByReference = false;
/**
* @var array|null
*/
protected $tokens = null;
/**
* @var null|NameInformation
*/
protected $nameInformation = null;
/**
* @param array $parameterTokens
* @param NameInformation $nameInformation
*/
public function __construct(array $parameterTokens, NameInformation $nameInformation = null)
{
$this->tokens = $parameterTokens;
$this->nameInformation = $nameInformation;
}
/**
* Set declaring class
*
* @param string $class
* @return void
*/
public function setDeclaringClass($class)
{
$this->declaringClass = (string) $class;
}
/**
* Set declaring scanner class
*
* @param ClassScanner $scannerClass
* @return void
*/
public function setDeclaringScannerClass(ClassScanner $scannerClass)
{
$this->declaringScannerClass = $scannerClass;
}
/**
* Set declaring function
*
* @param string $function
* @return void
*/
public function setDeclaringFunction($function)
{
$this->declaringFunction = $function;
}
/**
* Set declaring scanner function
*
* @param MethodScanner $scannerFunction
* @return void
*/
public function setDeclaringScannerFunction(MethodScanner $scannerFunction)
{
$this->declaringScannerFunction = $scannerFunction;
}
/**
* Set position
*
* @param int $position
* @return void
*/
public function setPosition($position)
{
$this->position = $position;
}
/**
* Scan
*
* @return void
*/
protected function scan()
{
if ($this->isScanned) {
return;
}
$tokens = &$this->tokens;
reset($tokens);
SCANNER_TOP:
$token = current($tokens);
if (is_string($token)) {
// check pass by ref
if ($token === '&') {
$this->isPassedByReference = true;
goto SCANNER_CONTINUE;
}
if ($token === '=') {
$this->isOptional = true;
$this->isDefaultValueAvailable = true;
goto SCANNER_CONTINUE;
}
} else {
if ($this->name === null && ($token[0] === T_STRING || $token[0] === T_NS_SEPARATOR)) {
$this->class .= $token[1];
goto SCANNER_CONTINUE;
}
if ($token[0] === T_VARIABLE) {
$this->name = ltrim($token[1], '$');
goto SCANNER_CONTINUE;
}
}
if ($this->name !== null) {
$this->defaultValue .= trim((is_string($token)) ? $token : $token[1]);
}
SCANNER_CONTINUE:
if (next($this->tokens) === false) {
goto SCANNER_END;
}
goto SCANNER_TOP;
SCANNER_END:
if ($this->class && $this->nameInformation) {
$this->class = $this->nameInformation->resolveName($this->class);
}
$this->isScanned = true;
}
/**
* Get declaring scanner class
*
* @return ClassScanner
*/
public function getDeclaringScannerClass()
{
return $this->declaringScannerClass;
}
/**
* Get declaring class
*
* @return string
*/
public function getDeclaringClass()
{
return $this->declaringClass;
}
/**
* Get declaring scanner function
*
* @return MethodScanner
*/
public function getDeclaringScannerFunction()
{
return $this->declaringScannerFunction;
}
/**
* Get declaring function
*
* @return string
*/
public function getDeclaringFunction()
{
return $this->declaringFunction;
}
/**
* Get default value
*
* @return string
*/
public function getDefaultValue()
{
$this->scan();
return $this->defaultValue;
}
/**
* Get class
*
* @return string
*/
public function getClass()
{
$this->scan();
return $this->class;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
$this->scan();
return $this->name;
}
/**
* Get position
*
* @return int
*/
public function getPosition()
{
$this->scan();
return $this->position;
}
/**
* Check if is array
*
* @return bool
*/
public function isArray()
{
$this->scan();
return $this->isArray;
}
/**
* Check if default value is available
*
* @return bool
*/
public function isDefaultValueAvailable()
{
$this->scan();
return $this->isDefaultValueAvailable;
}
/**
* Check if is optional
*
* @return bool
*/
public function isOptional()
{
$this->scan();
return $this->isOptional;
}
/**
* Check if is passed by reference
*
* @return bool
*/
public function isPassedByReference()
{
$this->scan();
return $this->isPassedByReference;
}
}

View File

@@ -0,0 +1,316 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Scanner;
use Zend\Code\Annotation;
use Zend\Code\Exception;
use Zend\Code\NameInformation;
class PropertyScanner implements ScannerInterface
{
const T_BOOLEAN = "boolean";
const T_INTEGER = "int";
const T_STRING = "string";
const T_ARRAY = "array";
const T_UNKNOWN = "unknown";
/**
* @var bool
*/
protected $isScanned = false;
/**
* @var array
*/
protected $tokens;
/**
* @var NameInformation
*/
protected $nameInformation;
/**
* @var string
*/
protected $class;
/**
* @var ClassScanner
*/
protected $scannerClass;
/**
* @var int
*/
protected $lineStart;
/**
* @var bool
*/
protected $isProtected = false;
/**
* @var bool
*/
protected $isPublic = true;
/**
* @var bool
*/
protected $isPrivate = false;
/**
* @var bool
*/
protected $isStatic = false;
/**
* @var string
*/
protected $docComment;
/**
* @var string
*/
protected $name;
/**
* @var string
*/
protected $value;
/**
* @var string
*/
protected $valueType;
/**
* Constructor
*
* @param array $propertyTokens
* @param NameInformation $nameInformation
*/
public function __construct(array $propertyTokens, NameInformation $nameInformation = null)
{
$this->tokens = $propertyTokens;
$this->nameInformation = $nameInformation;
}
/**
* @param string $class
*/
public function setClass($class)
{
$this->class = $class;
}
/**
* @param ClassScanner $scannerClass
*/
public function setScannerClass(ClassScanner $scannerClass)
{
$this->scannerClass = $scannerClass;
}
/**
* @return ClassScanner
*/
public function getClassScanner()
{
return $this->scannerClass;
}
/**
* @return string
*/
public function getName()
{
$this->scan();
return $this->name;
}
/**
* @return string
*/
public function getValueType()
{
return $this->valueType;
}
/**
* @return bool
*/
public function isPublic()
{
$this->scan();
return $this->isPublic;
}
/**
* @return bool
*/
public function isPrivate()
{
$this->scan();
return $this->isPrivate;
}
/**
* @return bool
*/
public function isProtected()
{
$this->scan();
return $this->isProtected;
}
/**
* @return bool
*/
public function isStatic()
{
$this->scan();
return $this->isStatic;
}
/**
* @return string
*/
public function getValue()
{
$this->scan();
return $this->value;
}
/**
* @return string
*/
public function getDocComment()
{
$this->scan();
return $this->docComment;
}
/**
* @param Annotation\AnnotationManager $annotationManager
* @return AnnotationScanner
*/
public function getAnnotations(Annotation\AnnotationManager $annotationManager)
{
if (($docComment = $this->getDocComment()) == '') {
return false;
}
return new AnnotationScanner($annotationManager, $docComment, $this->nameInformation);
}
/**
* @return string
*/
public function __toString()
{
$this->scan();
return var_export($this, true);
}
/**
* Scan tokens
*
* @throws \Zend\Code\Exception\RuntimeException
*/
protected function scan()
{
if ($this->isScanned) {
return;
}
if (!$this->tokens) {
throw new Exception\RuntimeException('No tokens were provided');
}
/**
* Variables & Setup
*/
$value = '';
$concatenateValue = false;
$tokens = &$this->tokens;
reset($tokens);
foreach ($tokens as $token) {
$tempValue = $token;
if (!is_string($token)) {
list($tokenType, $tokenContent, $tokenLine) = $token;
switch ($tokenType) {
case T_DOC_COMMENT:
if ($this->docComment === null && $this->name === null) {
$this->docComment = $tokenContent;
}
break;
case T_VARIABLE:
$this->name = ltrim($tokenContent, '$');
break;
case T_PUBLIC:
// use defaults
break;
case T_PROTECTED:
$this->isProtected = true;
$this->isPublic = false;
break;
case T_PRIVATE:
$this->isPrivate = true;
$this->isPublic = false;
break;
case T_STATIC:
$this->isStatic = true;
break;
default:
$tempValue = trim($tokenContent);
break;
}
}
//end value concatenation
if (!is_array($token) && trim($token) == ";") {
$concatenateValue = false;
}
if (true === $concatenateValue) {
$value .= $tempValue;
}
//start value concatenation
if (!is_array($token) && trim($token) == "=") {
$concatenateValue = true;
}
}
$this->valueType = self::T_UNKNOWN;
if ($value == "false" || $value == "true") {
$this->valueType = self::T_BOOLEAN;
} elseif (is_numeric($value)) {
$this->valueType = self::T_INTEGER;
} elseif (0 === strpos($value, 'array') || 0 === strpos($value, "[")) {
$this->valueType = self::T_ARRAY;
} elseif (substr($value, 0, 1) === '"' || substr($value, 0, 1) === "'") {
$value = substr($value, 1, -1); // Remove quotes
$this->valueType = self::T_STRING;
}
$this->value = empty($value) ? null : $value;
$this->isScanned = true;
}
}

View File

@@ -0,0 +1,16 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Scanner;
interface ScannerInterface
{
/* public static function export($tokens); */
/* public function toString(); */
}

View File

@@ -0,0 +1,689 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Scanner;
use Zend\Code\Annotation\AnnotationManager;
use Zend\Code\Exception;
use Zend\Code\NameInformation;
class TokenArrayScanner implements ScannerInterface
{
/**
* @var bool
*/
protected $isScanned = false;
/**
* @var array
*/
protected $tokens = array();
/**
* @var null
*/
protected $docComment = null;
/**
* @var NameInformation
*/
protected $nameInformation = null;
/**
* @var array
*/
protected $infos = array();
/**
* @var AnnotationManager
*/
protected $annotationManager = null;
/**
* @param null|array $tokens
* @param null|AnnotationManager $annotationManager
*/
public function __construct($tokens, AnnotationManager $annotationManager = null)
{
$this->tokens = $tokens;
$this->annotationManager = $annotationManager;
}
/**
* @return AnnotationManager
*/
public function getAnnotationManager()
{
return $this->annotationManager;
}
/**
* Get doc comment
*
* @todo Assignment of $this->docComment should probably be done in scan()
* and then $this->getDocComment() just retrieves it.
*
* @return string
*/
public function getDocComment()
{
foreach ($this->tokens as $token) {
$type = $token[0];
$value = $token[1];
if (($type == T_OPEN_TAG) || ($type == T_WHITESPACE)) {
continue;
} elseif ($type == T_DOC_COMMENT) {
$this->docComment = $value;
return $this->docComment;
} else {
// Only whitespace is allowed before file docblocks
return;
}
}
}
/**
* @return array
*/
public function getNamespaces()
{
$this->scan();
$namespaces = array();
foreach ($this->infos as $info) {
if ($info['type'] == 'namespace') {
$namespaces[] = $info['namespace'];
}
}
return $namespaces;
}
/**
* @param null|string $namespace
* @return array|null
*/
public function getUses($namespace = null)
{
$this->scan();
return $this->getUsesNoScan($namespace);
}
/**
* @return array
*/
public function getIncludes()
{
$this->scan();
// @todo Implement getIncludes() in TokenArrayScanner
}
/**
* @return array
*/
public function getClassNames()
{
$this->scan();
$return = array();
foreach ($this->infos as $info) {
if ($info['type'] != 'class') {
continue;
}
$return[] = $info['name'];
}
return $return;
}
/**
* @return ClassScanner[]
*/
public function getClasses()
{
$this->scan();
$return = array();
foreach ($this->infos as $info) {
if ($info['type'] != 'class') {
continue;
}
$return[] = $this->getClass($info['name']);
}
return $return;
}
/**
* Return the class object from this scanner
*
* @param string|int $name
* @throws Exception\InvalidArgumentException
* @return ClassScanner
*/
public function getClass($name)
{
$this->scan();
if (is_int($name)) {
$info = $this->infos[$name];
if ($info['type'] != 'class') {
throw new Exception\InvalidArgumentException('Index of info offset is not about a class');
}
} elseif (is_string($name)) {
$classFound = false;
foreach ($this->infos as $info) {
if ($info['type'] === 'class' && $info['name'] === $name) {
$classFound = true;
break;
}
}
if (!$classFound) {
return false;
}
}
return new ClassScanner(
array_slice(
$this->tokens,
$info['tokenStart'],
($info['tokenEnd'] - $info['tokenStart'] + 1)
), // zero indexed array
new NameInformation($info['namespace'], $info['uses'])
);
}
/**
* @param string $className
* @return bool|null|NameInformation
*/
public function getClassNameInformation($className)
{
$this->scan();
$classFound = false;
foreach ($this->infos as $info) {
if ($info['type'] === 'class' && $info['name'] === $className) {
$classFound = true;
break;
}
}
if (!$classFound) {
return false;
}
if (!isset($info)) {
return;
}
return new NameInformation($info['namespace'], $info['uses']);
}
/**
* @return array
*/
public function getFunctionNames()
{
$this->scan();
$functionNames = array();
foreach ($this->infos as $info) {
if ($info['type'] == 'function') {
$functionNames[] = $info['name'];
}
}
return $functionNames;
}
/**
* @return array
*/
public function getFunctions()
{
$this->scan();
$functions = array();
foreach ($this->infos as $info) {
if ($info['type'] == 'function') {
// @todo $functions[] = new FunctionScanner($info['name']);
}
}
return $functions;
}
/**
* Export
*
* @param $tokens
*/
public static function export($tokens)
{
// @todo
}
public function __toString()
{
// @todo
}
/**
* Scan
*
* @todo: $this->docComment should be assigned for valid docblock during
* the scan instead of $this->getDocComment() (starting with
* T_DOC_COMMENT case)
*
* @throws Exception\RuntimeException
*/
protected function scan()
{
if ($this->isScanned) {
return;
}
if (!$this->tokens) {
throw new Exception\RuntimeException('No tokens were provided');
}
/**
* Define PHP 5.4 'trait' token constant.
*/
if (!defined('T_TRAIT')) {
define('T_TRAIT', 42001);
}
/**
* Variables & Setup
*/
$tokens = &$this->tokens; // localize
$infos = &$this->infos; // localize
$tokenIndex = null;
$token = null;
$tokenType = null;
$tokenContent = null;
$tokenLine = null;
$namespace = null;
$docCommentIndex = false;
$infoIndex = 0;
/*
* MACRO creation
*/
$MACRO_TOKEN_ADVANCE = function () use (&$tokens, &$tokenIndex, &$token, &$tokenType, &$tokenContent, &$tokenLine) {
$tokenIndex = ($tokenIndex === null) ? 0 : $tokenIndex + 1;
if (!isset($tokens[$tokenIndex])) {
$token = false;
$tokenContent = false;
$tokenType = false;
$tokenLine = false;
return false;
}
if (is_string($tokens[$tokenIndex]) && $tokens[$tokenIndex] === '"') {
do {
$tokenIndex++;
} while (!(is_string($tokens[$tokenIndex]) && $tokens[$tokenIndex] === '"'));
}
$token = $tokens[$tokenIndex];
if (is_array($token)) {
list($tokenType, $tokenContent, $tokenLine) = $token;
} else {
$tokenType = null;
$tokenContent = $token;
}
return $tokenIndex;
};
$MACRO_TOKEN_LOGICAL_START_INDEX = function () use (&$tokenIndex, &$docCommentIndex) {
return ($docCommentIndex === false) ? $tokenIndex : $docCommentIndex;
};
$MACRO_DOC_COMMENT_START = function () use (&$tokenIndex, &$docCommentIndex) {
$docCommentIndex = $tokenIndex;
return $docCommentIndex;
};
$MACRO_DOC_COMMENT_VALIDATE = function () use (&$tokenType, &$docCommentIndex) {
static $validTrailingTokens = null;
if ($validTrailingTokens === null) {
$validTrailingTokens = array(T_WHITESPACE, T_FINAL, T_ABSTRACT, T_INTERFACE, T_CLASS, T_FUNCTION);
}
if ($docCommentIndex !== false && !in_array($tokenType, $validTrailingTokens)) {
$docCommentIndex = false;
}
return $docCommentIndex;
};
$MACRO_INFO_ADVANCE = function () use (&$infoIndex, &$infos, &$tokenIndex, &$tokenLine) {
$infos[$infoIndex]['tokenEnd'] = $tokenIndex;
$infos[$infoIndex]['lineEnd'] = $tokenLine;
$infoIndex++;
return $infoIndex;
};
/**
* START FINITE STATE MACHINE FOR SCANNING TOKENS
*/
// Initialize token
$MACRO_TOKEN_ADVANCE();
SCANNER_TOP:
if ($token === false) {
goto SCANNER_END;
}
// Validate current doc comment index
$MACRO_DOC_COMMENT_VALIDATE();
switch ($tokenType) {
case T_DOC_COMMENT:
$MACRO_DOC_COMMENT_START();
goto SCANNER_CONTINUE;
//goto no break needed
case T_NAMESPACE:
$infos[$infoIndex] = array(
'type' => 'namespace',
'tokenStart' => $MACRO_TOKEN_LOGICAL_START_INDEX(),
'tokenEnd' => null,
'lineStart' => $token[2],
'lineEnd' => null,
'namespace' => null,
);
// start processing with next token
if ($MACRO_TOKEN_ADVANCE() === false) {
goto SCANNER_END;
}
SCANNER_NAMESPACE_TOP:
if ($tokenType === null && $tokenContent === ';' || $tokenContent === '{') {
goto SCANNER_NAMESPACE_END;
}
if ($tokenType === T_WHITESPACE) {
goto SCANNER_NAMESPACE_CONTINUE;
}
if ($tokenType === T_NS_SEPARATOR || $tokenType === T_STRING) {
$infos[$infoIndex]['namespace'] .= $tokenContent;
}
SCANNER_NAMESPACE_CONTINUE:
if ($MACRO_TOKEN_ADVANCE() === false) {
goto SCANNER_END;
}
goto SCANNER_NAMESPACE_TOP;
SCANNER_NAMESPACE_END:
$namespace = $infos[$infoIndex]['namespace'];
$MACRO_INFO_ADVANCE();
goto SCANNER_CONTINUE;
//goto no break needed
case T_USE:
$infos[$infoIndex] = array(
'type' => 'use',
'tokenStart' => $MACRO_TOKEN_LOGICAL_START_INDEX(),
'tokenEnd' => null,
'lineStart' => $tokens[$tokenIndex][2],
'lineEnd' => null,
'namespace' => $namespace,
'statements' => array(0 => array('use' => null,
'as' => null)),
);
$useStatementIndex = 0;
$useAsContext = false;
// start processing with next token
if ($MACRO_TOKEN_ADVANCE() === false) {
goto SCANNER_END;
}
SCANNER_USE_TOP:
if ($tokenType === null) {
if ($tokenContent === ';') {
goto SCANNER_USE_END;
} elseif ($tokenContent === ',') {
$useAsContext = false;
$useStatementIndex++;
$infos[$infoIndex]['statements'][$useStatementIndex] = array('use' => null,
'as' => null);
}
}
// ANALYZE
if ($tokenType !== null) {
if ($tokenType == T_AS) {
$useAsContext = true;
goto SCANNER_USE_CONTINUE;
}
if ($tokenType == T_NS_SEPARATOR || $tokenType == T_STRING) {
if ($useAsContext == false) {
$infos[$infoIndex]['statements'][$useStatementIndex]['use'] .= $tokenContent;
} else {
$infos[$infoIndex]['statements'][$useStatementIndex]['as'] = $tokenContent;
}
}
}
SCANNER_USE_CONTINUE:
if ($MACRO_TOKEN_ADVANCE() === false) {
goto SCANNER_END;
}
goto SCANNER_USE_TOP;
SCANNER_USE_END:
$MACRO_INFO_ADVANCE();
goto SCANNER_CONTINUE;
//goto no break needed
case T_INCLUDE:
case T_INCLUDE_ONCE:
case T_REQUIRE:
case T_REQUIRE_ONCE:
// Static for performance
static $includeTypes = array(
T_INCLUDE => 'include',
T_INCLUDE_ONCE => 'include_once',
T_REQUIRE => 'require',
T_REQUIRE_ONCE => 'require_once'
);
$infos[$infoIndex] = array(
'type' => 'include',
'tokenStart' => $MACRO_TOKEN_LOGICAL_START_INDEX(),
'tokenEnd' => null,
'lineStart' => $tokens[$tokenIndex][2],
'lineEnd' => null,
'includeType' => $includeTypes[$tokens[$tokenIndex][0]],
'path' => '',
);
// start processing with next token
if ($MACRO_TOKEN_ADVANCE() === false) {
goto SCANNER_END;
}
SCANNER_INCLUDE_TOP:
if ($tokenType === null && $tokenContent === ';') {
goto SCANNER_INCLUDE_END;
}
$infos[$infoIndex]['path'] .= $tokenContent;
SCANNER_INCLUDE_CONTINUE:
if ($MACRO_TOKEN_ADVANCE() === false) {
goto SCANNER_END;
}
goto SCANNER_INCLUDE_TOP;
SCANNER_INCLUDE_END:
$MACRO_INFO_ADVANCE();
goto SCANNER_CONTINUE;
//goto no break needed
case T_FUNCTION:
case T_FINAL:
case T_ABSTRACT:
case T_CLASS:
case T_INTERFACE:
case T_TRAIT:
$infos[$infoIndex] = array(
'type' => ($tokenType === T_FUNCTION) ? 'function' : 'class',
'tokenStart' => $MACRO_TOKEN_LOGICAL_START_INDEX(),
'tokenEnd' => null,
'lineStart' => $tokens[$tokenIndex][2],
'lineEnd' => null,
'namespace' => $namespace,
'uses' => $this->getUsesNoScan($namespace),
'name' => null,
'shortName' => null,
);
$classBraceCount = 0;
// start processing with current token
SCANNER_CLASS_TOP:
// process the name
if ($infos[$infoIndex]['shortName'] == ''
&& (($tokenType === T_CLASS || $tokenType === T_INTERFACE || $tokenType === T_TRAIT) && $infos[$infoIndex]['type'] === 'class'
|| ($tokenType === T_FUNCTION && $infos[$infoIndex]['type'] === 'function'))
) {
$infos[$infoIndex]['shortName'] = $tokens[$tokenIndex + 2][1];
$infos[$infoIndex]['name'] = (($namespace !== null) ? $namespace . '\\' : '') . $infos[$infoIndex]['shortName'];
}
if ($tokenType === null) {
if ($tokenContent == '{') {
$classBraceCount++;
}
if ($tokenContent == '}') {
$classBraceCount--;
if ($classBraceCount === 0) {
goto SCANNER_CLASS_END;
}
}
}
SCANNER_CLASS_CONTINUE:
if ($MACRO_TOKEN_ADVANCE() === false) {
goto SCANNER_END;
}
goto SCANNER_CLASS_TOP;
SCANNER_CLASS_END:
$MACRO_INFO_ADVANCE();
goto SCANNER_CONTINUE;
}
SCANNER_CONTINUE:
if ($MACRO_TOKEN_ADVANCE() === false) {
goto SCANNER_END;
}
goto SCANNER_TOP;
SCANNER_END:
/**
* END FINITE STATE MACHINE FOR SCANNING TOKENS
*/
$this->isScanned = true;
}
/**
* Check for namespace
*
* @param string $namespace
* @return bool
*/
public function hasNamespace($namespace)
{
$this->scan();
foreach ($this->infos as $info) {
if ($info['type'] == 'namespace' && $info['namespace'] == $namespace) {
return true;
}
}
return false;
}
/**
* @param string $namespace
* @return null|array
* @throws Exception\InvalidArgumentException
*/
protected function getUsesNoScan($namespace)
{
$namespaces = array();
foreach ($this->infos as $info) {
if ($info['type'] == 'namespace') {
$namespaces[] = $info['namespace'];
}
}
if ($namespace === null) {
$namespace = array_shift($namespaces);
} elseif (!is_string($namespace)) {
throw new Exception\InvalidArgumentException('Invalid namespace provided');
} elseif (!in_array($namespace, $namespaces)) {
return;
}
$uses = array();
foreach ($this->infos as $info) {
if ($info['type'] !== 'use') {
continue;
}
foreach ($info['statements'] as $statement) {
if ($info['namespace'] == $namespace) {
$uses[] = $statement;
}
}
}
return $uses;
}
}

View File

@@ -0,0 +1,74 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Scanner;
use stdClass;
use Zend\Code\Exception;
/**
* Shared utility methods used by scanners
*/
class Util
{
/**
* Resolve imports
*
* @param string $value
* @param null|string $key
* @param \stdClass $data
* @return void
* @throws Exception\InvalidArgumentException
*/
public static function resolveImports(&$value, $key = null, stdClass $data = null)
{
if (!is_object($data)
|| !property_exists($data, 'uses')
|| !property_exists($data, 'namespace')
) {
throw new Exception\InvalidArgumentException(sprintf(
'%s expects a data object containing "uses" and "namespace" properties; on or both missing',
__METHOD__
));
}
if ($data->namespace && !$data->uses && strlen($value) > 0 && $value{0} != '\\') {
$value = $data->namespace . '\\' . $value;
return;
}
if (!$data->uses || strlen($value) <= 0 || $value{0} == '\\') {
$value = ltrim($value, '\\');
return;
}
if ($data->namespace || $data->uses) {
$firstPart = $value;
if (($firstPartEnd = strpos($firstPart, '\\')) !== false) {
$firstPart = substr($firstPart, 0, $firstPartEnd);
} else {
$firstPartEnd = strlen($firstPart);
}
if (array_key_exists($firstPart, $data->uses)) {
$value = substr_replace($value, $data->uses[$firstPart], 0, $firstPartEnd);
return;
}
if ($data->namespace) {
$value = $data->namespace . '\\' . $value;
return;
}
}
}
}

View File

@@ -0,0 +1,15 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Zend\Code\Scanner;
class ValueScanner
{
// @todo
}