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,28 @@
Copyright (c) 2005-2015, Zend Technologies USA, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
- Neither the name of Zend Technologies USA, Inc. nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,43 @@
{
"name": "zendframework/zend-code",
"description": "provides facilities to generate arbitrary code using an object oriented interface",
"license": "BSD-3-Clause",
"keywords": [
"zf2",
"code"
],
"homepage": "https://github.com/zendframework/zend-code",
"autoload": {
"psr-4": {
"Zend\\Code\\": "src/"
}
},
"require": {
"php": ">=5.3.23",
"zendframework/zend-eventmanager": "~2.5"
},
"require-dev": {
"doctrine/common": ">=2.1",
"zendframework/zend-stdlib": "~2.5",
"zendframework/zend-version": "~2.5",
"fabpot/php-cs-fixer": "1.7.*",
"phpunit/PHPUnit": "~4.0"
},
"suggest": {
"doctrine/common": "Doctrine\\Common >=2.1 for annotation features",
"zendframework/zend-stdlib": "Zend\\Stdlib component"
},
"minimum-stability": "dev",
"prefer-stable": true,
"extra": {
"branch-alias": {
"dev-master": "2.5-dev",
"dev-develop": "2.6-dev"
}
},
"autoload-dev": {
"psr-4": {
"ZendTest\\Code\\": "test/"
}
}
}

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
}

View File

@ -0,0 +1,28 @@
Copyright (c) 2005-2015, Zend Technologies USA, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
- Neither the name of Zend Technologies USA, Inc. nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,36 @@
{
"name": "zendframework/zend-eventmanager",
"description": " ",
"license": "BSD-3-Clause",
"keywords": [
"zf2",
"eventmanager"
],
"homepage": "https://github.com/zendframework/zend-eventmanager",
"autoload": {
"psr-4": {
"Zend\\EventManager\\": "src/"
}
},
"require": {
"php": ">=5.3.23",
"zendframework/zend-stdlib": "~2.5"
},
"minimum-stability": "dev",
"prefer-stable": true,
"extra": {
"branch-alias": {
"dev-master": "2.5-dev",
"dev-develop": "2.6-dev"
}
},
"autoload-dev": {
"psr-4": {
"ZendTest\\EventManager\\": "test/"
}
},
"require-dev": {
"fabpot/php-cs-fixer": "1.7.*",
"phpunit/PHPUnit": "~4.0"
}
}

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\EventManager;
/**
* Abstract aggregate listener
*/
abstract class AbstractListenerAggregate implements ListenerAggregateInterface
{
/**
* @var \Zend\Stdlib\CallbackHandler[]
*/
protected $listeners = array();
/**
* {@inheritDoc}
*/
public function detach(EventManagerInterface $events)
{
foreach ($this->listeners as $index => $callback) {
if ($events->detach($callback)) {
unset($this->listeners[$index]);
}
}
}
}

View File

@ -0,0 +1,209 @@
<?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\EventManager;
use ArrayAccess;
/**
* Representation of an event
*
* Encapsulates the target context and parameters passed, and provides some
* behavior for interacting with the event manager.
*/
class Event implements EventInterface
{
/**
* @var string Event name
*/
protected $name;
/**
* @var string|object The event target
*/
protected $target;
/**
* @var array|ArrayAccess|object The event parameters
*/
protected $params = array();
/**
* @var bool Whether or not to stop propagation
*/
protected $stopPropagation = false;
/**
* Constructor
*
* Accept a target and its parameters.
*
* @param string $name Event name
* @param string|object $target
* @param array|ArrayAccess $params
*/
public function __construct($name = null, $target = null, $params = null)
{
if (null !== $name) {
$this->setName($name);
}
if (null !== $target) {
$this->setTarget($target);
}
if (null !== $params) {
$this->setParams($params);
}
}
/**
* Get event name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Get the event target
*
* This may be either an object, or the name of a static method.
*
* @return string|object
*/
public function getTarget()
{
return $this->target;
}
/**
* Set parameters
*
* Overwrites parameters
*
* @param array|ArrayAccess|object $params
* @return Event
* @throws Exception\InvalidArgumentException
*/
public function setParams($params)
{
if (!is_array($params) && !is_object($params)) {
throw new Exception\InvalidArgumentException(
sprintf('Event parameters must be an array or object; received "%s"', gettype($params))
);
}
$this->params = $params;
return $this;
}
/**
* Get all parameters
*
* @return array|object|ArrayAccess
*/
public function getParams()
{
return $this->params;
}
/**
* Get an individual parameter
*
* If the parameter does not exist, the $default value will be returned.
*
* @param string|int $name
* @param mixed $default
* @return mixed
*/
public function getParam($name, $default = null)
{
// Check in params that are arrays or implement array access
if (is_array($this->params) || $this->params instanceof ArrayAccess) {
if (!isset($this->params[$name])) {
return $default;
}
return $this->params[$name];
}
// Check in normal objects
if (!isset($this->params->{$name})) {
return $default;
}
return $this->params->{$name};
}
/**
* Set the event name
*
* @param string $name
* @return Event
*/
public function setName($name)
{
$this->name = (string) $name;
return $this;
}
/**
* Set the event target/context
*
* @param null|string|object $target
* @return Event
*/
public function setTarget($target)
{
$this->target = $target;
return $this;
}
/**
* Set an individual parameter to a value
*
* @param string|int $name
* @param mixed $value
* @return Event
*/
public function setParam($name, $value)
{
if (is_array($this->params) || $this->params instanceof ArrayAccess) {
// Arrays or objects implementing array access
$this->params[$name] = $value;
} else {
// Objects
$this->params->{$name} = $value;
}
return $this;
}
/**
* Stop further event propagation
*
* @param bool $flag
* @return void
*/
public function stopPropagation($flag = true)
{
$this->stopPropagation = (bool) $flag;
}
/**
* Is propagation stopped?
*
* @return bool
*/
public function propagationIsStopped()
{
return $this->stopPropagation;
}
}

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\EventManager;
use ArrayAccess;
/**
* Representation of an event
*/
interface EventInterface
{
/**
* Get event name
*
* @return string
*/
public function getName();
/**
* Get target/context from which event was triggered
*
* @return null|string|object
*/
public function getTarget();
/**
* Get parameters passed to the event
*
* @return array|ArrayAccess
*/
public function getParams();
/**
* Get a single parameter by name
*
* @param string $name
* @param mixed $default Default value to return if parameter does not exist
* @return mixed
*/
public function getParam($name, $default = null);
/**
* Set the event name
*
* @param string $name
* @return void
*/
public function setName($name);
/**
* Set the event target/context
*
* @param null|string|object $target
* @return void
*/
public function setTarget($target);
/**
* Set event parameters
*
* @param string $params
* @return void
*/
public function setParams($params);
/**
* Set a single parameter by key
*
* @param string $name
* @param mixed $value
* @return void
*/
public function setParam($name, $value);
/**
* Indicate whether or not the parent EventManagerInterface should stop propagating events
*
* @param bool $flag
* @return void
*/
public function stopPropagation($flag = true);
/**
* Has this event indicated event propagation should stop?
*
* @return bool
*/
public function propagationIsStopped();
}

View File

@ -0,0 +1,526 @@
<?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\EventManager;
use ArrayAccess;
use ArrayObject;
use Traversable;
use Zend\Stdlib\CallbackHandler;
use Zend\Stdlib\PriorityQueue;
/**
* Event manager: notification system
*
* Use the EventManager when you want to create a per-instance notification
* system for your objects.
*/
class EventManager implements EventManagerInterface
{
/**
* Subscribed events and their listeners
* @var array Array of PriorityQueue objects
*/
protected $events = array();
/**
* @var string Class representing the event being emitted
*/
protected $eventClass = 'Zend\EventManager\Event';
/**
* Identifiers, used to pull shared signals from SharedEventManagerInterface instance
* @var array
*/
protected $identifiers = array();
/**
* Shared event manager
* @var false|null|SharedEventManagerInterface
*/
protected $sharedManager = null;
/**
* Constructor
*
* Allows optionally specifying identifier(s) to use to pull signals from a
* SharedEventManagerInterface.
*
* @param null|string|int|array|Traversable $identifiers
*/
public function __construct($identifiers = null)
{
$this->setIdentifiers($identifiers);
}
/**
* Set the event class to utilize
*
* @param string $class
* @return EventManager
*/
public function setEventClass($class)
{
$this->eventClass = $class;
return $this;
}
/**
* Set shared event manager
*
* @param SharedEventManagerInterface $sharedEventManager
* @return EventManager
*/
public function setSharedManager(SharedEventManagerInterface $sharedEventManager)
{
$this->sharedManager = $sharedEventManager;
StaticEventManager::setInstance($sharedEventManager);
return $this;
}
/**
* Remove any shared event manager currently attached
*
* @return void
*/
public function unsetSharedManager()
{
$this->sharedManager = false;
}
/**
* Get shared event manager
*
* If one is not defined, but we have a static instance in
* StaticEventManager, that one will be used and set in this instance.
*
* If none is available in the StaticEventManager, a boolean false is
* returned.
*
* @return false|SharedEventManagerInterface
*/
public function getSharedManager()
{
// "false" means "I do not want a shared manager; don't try and fetch one"
if (false === $this->sharedManager
|| $this->sharedManager instanceof SharedEventManagerInterface
) {
return $this->sharedManager;
}
if (!StaticEventManager::hasInstance()) {
return false;
}
$this->sharedManager = StaticEventManager::getInstance();
return $this->sharedManager;
}
/**
* Get the identifier(s) for this EventManager
*
* @return array
*/
public function getIdentifiers()
{
return $this->identifiers;
}
/**
* Set the identifiers (overrides any currently set identifiers)
*
* @param string|int|array|Traversable $identifiers
* @return EventManager Provides a fluent interface
*/
public function setIdentifiers($identifiers)
{
if (is_array($identifiers) || $identifiers instanceof Traversable) {
$this->identifiers = array_unique((array) $identifiers);
} elseif ($identifiers !== null) {
$this->identifiers = array($identifiers);
}
return $this;
}
/**
* Add some identifier(s) (appends to any currently set identifiers)
*
* @param string|int|array|Traversable $identifiers
* @return EventManager Provides a fluent interface
*/
public function addIdentifiers($identifiers)
{
if (is_array($identifiers) || $identifiers instanceof Traversable) {
$this->identifiers = array_unique(array_merge($this->identifiers, (array) $identifiers));
} elseif ($identifiers !== null) {
$this->identifiers = array_unique(array_merge($this->identifiers, array($identifiers)));
}
return $this;
}
/**
* Trigger all listeners for a given event
*
* @param string|EventInterface $event
* @param string|object $target Object calling emit, or symbol describing target (such as static method name)
* @param array|ArrayAccess $argv Array of arguments; typically, should be associative
* @param null|callable $callback Trigger listeners until return value of this callback evaluate to true
* @return ResponseCollection All listener return values
* @throws Exception\InvalidCallbackException
*/
public function trigger($event, $target = null, $argv = array(), $callback = null)
{
if ($event instanceof EventInterface) {
$e = $event;
$event = $e->getName();
$callback = $target;
} elseif ($target instanceof EventInterface) {
$e = $target;
$e->setName($event);
$callback = $argv;
} elseif ($argv instanceof EventInterface) {
$e = $argv;
$e->setName($event);
$e->setTarget($target);
} else {
$e = new $this->eventClass();
$e->setName($event);
$e->setTarget($target);
$e->setParams($argv);
}
if ($callback && !is_callable($callback)) {
throw new Exception\InvalidCallbackException('Invalid callback provided');
}
// Initial value of stop propagation flag should be false
$e->stopPropagation(false);
return $this->triggerListeners($event, $e, $callback);
}
/**
* Trigger listeners until return value of one causes a callback to
* evaluate to true
*
* Triggers listeners until the provided callback evaluates the return
* value of one as true, or until all listeners have been executed.
*
* @param string|EventInterface $event
* @param string|object $target Object calling emit, or symbol describing target (such as static method name)
* @param array|ArrayAccess $argv Array of arguments; typically, should be associative
* @param callable $callback
* @return ResponseCollection
* @deprecated Please use trigger()
* @throws Exception\InvalidCallbackException if invalid callable provided
*/
public function triggerUntil($event, $target, $argv = null, $callback = null)
{
trigger_error(
'This method is deprecated and will be removed in the future. Please use trigger() instead.',
E_USER_DEPRECATED
);
return $this->trigger($event, $target, $argv, $callback);
}
/**
* Attach a listener to an event
*
* The first argument is the event, and the next argument describes a
* callback that will respond to that event. A CallbackHandler instance
* describing the event listener combination will be returned.
*
* The last argument indicates a priority at which the event should be
* executed. By default, this value is 1; however, you may set it for any
* integer value. Higher values have higher priority (i.e., execute first).
*
* You can specify "*" for the event name. In such cases, the listener will
* be triggered for every event.
*
* @param string|array|ListenerAggregateInterface $event An event or array of event names. If a ListenerAggregateInterface, proxies to {@link attachAggregate()}.
* @param callable|int $callback If string $event provided, expects PHP callback; for a ListenerAggregateInterface $event, this will be the priority
* @param int $priority If provided, the priority at which to register the callable
* @return CallbackHandler|mixed CallbackHandler if attaching callable (to allow later unsubscribe); mixed if attaching aggregate
* @throws Exception\InvalidArgumentException
*/
public function attach($event, $callback = null, $priority = 1)
{
// Proxy ListenerAggregateInterface arguments to attachAggregate()
if ($event instanceof ListenerAggregateInterface) {
return $this->attachAggregate($event, $callback);
}
// Null callback is invalid
if (null === $callback) {
throw new Exception\InvalidArgumentException(sprintf(
'%s: expects a callback; none provided',
__METHOD__
));
}
// Array of events should be registered individually, and return an array of all listeners
if (is_array($event)) {
$listeners = array();
foreach ($event as $name) {
$listeners[] = $this->attach($name, $callback, $priority);
}
return $listeners;
}
// If we don't have a priority queue for the event yet, create one
if (empty($this->events[$event])) {
$this->events[$event] = new PriorityQueue();
}
// Create a callback handler, setting the event and priority in its metadata
$listener = new CallbackHandler($callback, array('event' => $event, 'priority' => $priority));
// Inject the callback handler into the queue
$this->events[$event]->insert($listener, $priority);
return $listener;
}
/**
* Attach a listener aggregate
*
* Listener aggregates accept an EventManagerInterface instance, and call attach()
* one or more times, typically to attach to multiple events using local
* methods.
*
* @param ListenerAggregateInterface $aggregate
* @param int $priority If provided, a suggested priority for the aggregate to use
* @return mixed return value of {@link ListenerAggregateInterface::attach()}
*/
public function attachAggregate(ListenerAggregateInterface $aggregate, $priority = 1)
{
return $aggregate->attach($this, $priority);
}
/**
* Unsubscribe a listener from an event
*
* @param CallbackHandler|ListenerAggregateInterface $listener
* @return bool Returns true if event and listener found, and unsubscribed; returns false if either event or listener not found
* @throws Exception\InvalidArgumentException if invalid listener provided
*/
public function detach($listener)
{
if ($listener instanceof ListenerAggregateInterface) {
return $this->detachAggregate($listener);
}
if (!$listener instanceof CallbackHandler) {
throw new Exception\InvalidArgumentException(sprintf(
'%s: expected a ListenerAggregateInterface or CallbackHandler; received "%s"',
__METHOD__,
(is_object($listener) ? get_class($listener) : gettype($listener))
));
}
$event = $listener->getMetadatum('event');
if (!$event || empty($this->events[$event])) {
return false;
}
$return = $this->events[$event]->remove($listener);
if (!$return) {
return false;
}
if (!count($this->events[$event])) {
unset($this->events[$event]);
}
return true;
}
/**
* Detach a listener aggregate
*
* Listener aggregates accept an EventManagerInterface instance, and call detach()
* of all previously attached listeners.
*
* @param ListenerAggregateInterface $aggregate
* @return mixed return value of {@link ListenerAggregateInterface::detach()}
*/
public function detachAggregate(ListenerAggregateInterface $aggregate)
{
return $aggregate->detach($this);
}
/**
* Retrieve all registered events
*
* @return array
*/
public function getEvents()
{
return array_keys($this->events);
}
/**
* Retrieve all listeners for a given event
*
* @param string $event
* @return PriorityQueue
*/
public function getListeners($event)
{
if (!array_key_exists($event, $this->events)) {
return new PriorityQueue();
}
return $this->events[$event];
}
/**
* Clear all listeners for a given event
*
* @param string $event
* @return void
*/
public function clearListeners($event)
{
if (!empty($this->events[$event])) {
unset($this->events[$event]);
}
}
/**
* Prepare arguments
*
* Use this method if you want to be able to modify arguments from within a
* listener. It returns an ArrayObject of the arguments, which may then be
* passed to trigger().
*
* @param array $args
* @return ArrayObject
*/
public function prepareArgs(array $args)
{
return new ArrayObject($args);
}
/**
* Trigger listeners
*
* Actual functionality for triggering listeners, to which trigger() delegate.
*
* @param string $event Event name
* @param EventInterface $e
* @param null|callable $callback
* @return ResponseCollection
*/
protected function triggerListeners($event, EventInterface $e, $callback = null)
{
$responses = new ResponseCollection;
$listeners = $this->getListeners($event);
// Add shared/wildcard listeners to the list of listeners,
// but don't modify the listeners object
$sharedListeners = $this->getSharedListeners($event);
$sharedWildcardListeners = $this->getSharedListeners('*');
$wildcardListeners = $this->getListeners('*');
if (count($sharedListeners) || count($sharedWildcardListeners) || count($wildcardListeners)) {
$listeners = clone $listeners;
// Shared listeners on this specific event
$this->insertListeners($listeners, $sharedListeners);
// Shared wildcard listeners
$this->insertListeners($listeners, $sharedWildcardListeners);
// Add wildcard listeners
$this->insertListeners($listeners, $wildcardListeners);
}
foreach ($listeners as $listener) {
$listenerCallback = $listener->getCallback();
// Trigger the listener's callback, and push its result onto the
// response collection
$responses->push(call_user_func($listenerCallback, $e));
// If the event was asked to stop propagating, do so
if ($e->propagationIsStopped()) {
$responses->setStopped(true);
break;
}
// If the result causes our validation callback to return true,
// stop propagation
if ($callback && call_user_func($callback, $responses->last())) {
$responses->setStopped(true);
break;
}
}
return $responses;
}
/**
* Get list of all listeners attached to the shared event manager for
* identifiers registered by this instance
*
* @param string $event
* @return array
*/
protected function getSharedListeners($event)
{
if (!$sharedManager = $this->getSharedManager()) {
return array();
}
$identifiers = $this->getIdentifiers();
//Add wildcard id to the search, if not already added
if (!in_array('*', $identifiers)) {
$identifiers[] = '*';
}
$sharedListeners = array();
foreach ($identifiers as $id) {
if (!$listeners = $sharedManager->getListeners($id, $event)) {
continue;
}
if (!is_array($listeners) && !($listeners instanceof Traversable)) {
continue;
}
foreach ($listeners as $listener) {
if (!$listener instanceof CallbackHandler) {
continue;
}
$sharedListeners[] = $listener;
}
}
return $sharedListeners;
}
/**
* Add listeners to the master queue of listeners
*
* Used to inject shared listeners and wildcard listeners.
*
* @param PriorityQueue $masterListeners
* @param array|Traversable $listeners
* @return void
*/
protected function insertListeners($masterListeners, $listeners)
{
foreach ($listeners as $listener) {
$priority = $listener->getMetadatum('priority');
if (null === $priority) {
$priority = 1;
} elseif (is_array($priority)) {
// If we have an array, likely using PriorityQueue. Grab first
// element of the array, as that's the actual priority.
$priority = array_shift($priority);
}
$masterListeners->insert($listener, $priority);
}
}
}

View File

@ -0,0 +1,24 @@
<?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\EventManager;
/**
* Interface to automate setter injection for an EventManager instance
*/
interface EventManagerAwareInterface extends EventsCapableInterface
{
/**
* Inject an EventManager instance
*
* @param EventManagerInterface $eventManager
* @return void
*/
public function setEventManager(EventManagerInterface $eventManager);
}

View File

@ -0,0 +1,77 @@
<?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\EventManager;
use Traversable;
/**
* A trait for objects that provide events.
*
* If you use this trait in an object, you will probably want to also implement
* EventManagerAwareInterface, which will make it so the default initializer in
* a ZF2 MVC application will automatically inject an instance of the
* EventManager into your object when it is pulled from the ServiceManager.
*
* @see Zend\Mvc\Service\ServiceManagerConfig
*/
trait EventManagerAwareTrait
{
/**
* @var EventManagerInterface
*/
protected $events;
/**
* Set the event manager instance used by this context.
*
* For convenience, this method will also set the class name / LSB name as
* identifiers, in addition to any string or array of strings set to the
* $this->eventIdentifier property.
*
* @param EventManagerInterface $events
* @return mixed
*/
public function setEventManager(EventManagerInterface $events)
{
$identifiers = array(__CLASS__, get_class($this));
if (isset($this->eventIdentifier)) {
if ((is_string($this->eventIdentifier))
|| (is_array($this->eventIdentifier))
|| ($this->eventIdentifier instanceof Traversable)
) {
$identifiers = array_unique(array_merge($identifiers, (array) $this->eventIdentifier));
} elseif (is_object($this->eventIdentifier)) {
$identifiers[] = $this->eventIdentifier;
}
// silently ignore invalid eventIdentifier types
}
$events->setIdentifiers($identifiers);
$this->events = $events;
if (method_exists($this, 'attachDefaultListeners')) {
$this->attachDefaultListeners();
}
return $this;
}
/**
* Retrieve the event manager
*
* Lazy-loads an EventManager instance if none registered.
*
* @return EventManagerInterface
*/
public function getEventManager()
{
if (!$this->events instanceof EventManagerInterface) {
$this->setEventManager(new EventManager());
}
return $this->events;
}
}

View File

@ -0,0 +1,144 @@
<?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\EventManager;
use Traversable;
use Zend\Stdlib\CallbackHandler;
/**
* Interface for messengers
*/
interface EventManagerInterface extends SharedEventManagerAwareInterface
{
/**
* Trigger an event
*
* Should allow handling the following scenarios:
* - Passing Event object only
* - Passing event name and Event object only
* - Passing event name, target, and Event object
* - Passing event name, target, and array|ArrayAccess of arguments
* - Passing event name, target, array|ArrayAccess of arguments, and callback
*
* @param string|EventInterface $event
* @param object|string $target
* @param array|object $argv
* @param null|callable $callback
* @return ResponseCollection
*/
public function trigger($event, $target = null, $argv = array(), $callback = null);
/**
* Trigger an event until the given callback returns a boolean true
*
* Should allow handling the following scenarios:
* - Passing Event object and callback only
* - Passing event name, Event object, and callback only
* - Passing event name, target, Event object, and callback
* - Passing event name, target, array|ArrayAccess of arguments, and callback
*
* @param string|EventInterface $event
* @param object|string $target
* @param array|object $argv
* @param callable $callback
* @return ResponseCollection
* @deprecated Please use trigger()
*/
public function triggerUntil($event, $target, $argv = null, $callback = null);
/**
* Attach a listener to an event
*
* @param string $event
* @param callable $callback
* @param int $priority Priority at which to register listener
* @return CallbackHandler
*/
public function attach($event, $callback = null, $priority = 1);
/**
* Detach an event listener
*
* @param CallbackHandler|ListenerAggregateInterface $listener
* @return bool
*/
public function detach($listener);
/**
* Get a list of events for which this collection has listeners
*
* @return array
*/
public function getEvents();
/**
* Retrieve a list of listeners registered to a given event
*
* @param string $event
* @return array|object
*/
public function getListeners($event);
/**
* Clear all listeners for a given event
*
* @param string $event
* @return void
*/
public function clearListeners($event);
/**
* Set the event class to utilize
*
* @param string $class
* @return EventManagerInterface
*/
public function setEventClass($class);
/**
* Get the identifier(s) for this EventManager
*
* @return array
*/
public function getIdentifiers();
/**
* Set the identifiers (overrides any currently set identifiers)
*
* @param string|int|array|Traversable $identifiers
* @return EventManagerInterface
*/
public function setIdentifiers($identifiers);
/**
* Add some identifier(s) (appends to any currently set identifiers)
*
* @param string|int|array|Traversable $identifiers
* @return EventManagerInterface
*/
public function addIdentifiers($identifiers);
/**
* Attach a listener aggregate
*
* @param ListenerAggregateInterface $aggregate
* @param int $priority If provided, a suggested priority for the aggregate to use
* @return mixed return value of {@link ListenerAggregateInterface::attach()}
*/
public function attachAggregate(ListenerAggregateInterface $aggregate, $priority = 1);
/**
* Detach a listener aggregate
*
* @param ListenerAggregateInterface $aggregate
* @return mixed return value of {@link ListenerAggregateInterface::detach()}
*/
public function detachAggregate(ListenerAggregateInterface $aggregate);
}

View File

@ -0,0 +1,25 @@
<?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\EventManager;
/**
* Interface providing events that can be attached, detached and triggered.
*/
interface EventsCapableInterface
{
/**
* Retrieve the event manager
*
* Lazy-loads an EventManager instance if none registered.
*
* @return EventManagerInterface
*/
public function getEventManager();
}

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\EventManager\Exception;
class DomainException extends \DomainException 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\EventManager\Exception;
/**
* Base exception interface
*/
interface 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\EventManager\Exception;
/**
* Invalid argument exception
*/
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}

Some files were not shown because too many files have changed in this diff Show More