279 lines
6.4 KiB
PHP
279 lines
6.4 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace Laminas\Code\Reflection;
|
||
|
|
|
||
|
|
use Laminas\Code\Reflection\DocBlock\Tag\TagInterface as DocBlockTagInterface;
|
||
|
|
use Laminas\Code\Reflection\DocBlock\TagManager as DocBlockTagManager;
|
||
|
|
use Laminas\Code\Scanner\DocBlockScanner;
|
||
|
|
use Reflector;
|
||
|
|
|
||
|
|
use function count;
|
||
|
|
use function is_string;
|
||
|
|
use function ltrim;
|
||
|
|
use function method_exists;
|
||
|
|
use function preg_replace;
|
||
|
|
use function sprintf;
|
||
|
|
use function substr_count;
|
||
|
|
|
||
|
|
class DocBlockReflection implements ReflectionInterface
|
||
|
|
{
|
||
|
|
/** @var Reflector */
|
||
|
|
protected $reflector;
|
||
|
|
|
||
|
|
/** @var string */
|
||
|
|
protected $docComment;
|
||
|
|
|
||
|
|
/** @var DocBlockTagManager */
|
||
|
|
protected $tagManager;
|
||
|
|
|
||
|
|
/** @var int */
|
||
|
|
protected $startLine;
|
||
|
|
|
||
|
|
/** @var int */
|
||
|
|
protected $endLine;
|
||
|
|
|
||
|
|
/** @var string */
|
||
|
|
protected $cleanDocComment;
|
||
|
|
|
||
|
|
/** @var string */
|
||
|
|
protected $longDescription;
|
||
|
|
|
||
|
|
/** @var string */
|
||
|
|
protected $shortDescription;
|
||
|
|
|
||
|
|
/** @var array */
|
||
|
|
protected $tags = [];
|
||
|
|
|
||
|
|
/** @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
|
||
|
|
* @throws Exception\InvalidArgumentException
|
||
|
|
*/
|
||
|
|
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"');
|
||
|
|
}
|
||
|
|
|
||
|
|
$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',
|
||
|
|
static::class
|
||
|
|
));
|
||
|
|
}
|
||
|
|
|
||
|
|
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 = [];
|
||
|
|
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);
|
||
|
|
|
||
|
|
// @todo should be changed to remove first and last empty line
|
||
|
|
$this->cleanDocComment = ltrim($this->cleanDocComment, "\r\n");
|
||
|
|
|
||
|
|
$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 */ ] {' . "\n\n";
|
||
|
|
$str .= ' - Tags [' . count($this->tags) . '] {' . "\n";
|
||
|
|
|
||
|
|
foreach ($this->tags as $tag) {
|
||
|
|
$str .= ' ' . $tag;
|
||
|
|
}
|
||
|
|
|
||
|
|
$str .= ' }' . "\n";
|
||
|
|
$str .= '}' . "\n";
|
||
|
|
|
||
|
|
return $str;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Serialize to string
|
||
|
|
*
|
||
|
|
* Required by the Reflector interface
|
||
|
|
*/
|
||
|
|
public function __toString(): string
|
||
|
|
{
|
||
|
|
return $this->toString();
|
||
|
|
}
|
||
|
|
}
|