changes for filter and print

This commit is contained in:
2024-09-29 16:59:27 +05:45
parent 497f567cba
commit 684e01bf48
1335 changed files with 38709 additions and 74987 deletions

View File

@ -1,6 +1,5 @@
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
![Qa workflow](https://github.com/phpDocumentor/ReflectionDocBlock/workflows/Qa%20workflow/badge.svg)
[![Coveralls Coverage](https://img.shields.io/coveralls/github/phpDocumentor/ReflectionDocBlock.svg)](https://coveralls.io/github/phpDocumentor/ReflectionDocBlock?branch=master)
[![Scrutinizer Code Coverage](https://img.shields.io/scrutinizer/coverage/g/phpDocumentor/ReflectionDocBlock.svg)](https://scrutinizer-ci.com/g/phpDocumentor/ReflectionDocBlock/?branch=master)
[![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/phpDocumentor/ReflectionDocBlock.svg)](https://scrutinizer-ci.com/g/phpDocumentor/ReflectionDocBlock/?branch=master)
[![Stable Version](https://img.shields.io/packagist/v/phpdocumentor/reflection-docblock.svg)](https://packagist.org/packages/phpdocumentor/reflection-docblock)

View File

@ -10,19 +10,26 @@
},
{
"name": "Jaap van Otterdijk",
"email": "account@ijaap.nl"
"email": "opensource@ijaap.nl"
}
],
"require": {
"php": "^7.2 || ^8.0",
"phpdocumentor/type-resolver": "^1.3",
"php": "^7.4 || ^8.0",
"phpdocumentor/type-resolver": "^1.7",
"webmozart/assert": "^1.9.1",
"phpdocumentor/reflection-common": "^2.2",
"ext-filter": "*"
"ext-filter": "*",
"phpstan/phpdoc-parser": "^1.7",
"doctrine/deprecations": "^1.1"
},
"require-dev": {
"mockery/mockery": "~1.3.2",
"psalm/phar": "^4.8"
"mockery/mockery": "~1.3.5",
"phpunit/phpunit": "^9.5",
"phpstan/phpstan": "^1.8",
"phpstan/phpstan-mockery": "^1.1",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan-webmozart-assert": "^1.2",
"vimeo/psalm": "^5.13"
},
"autoload": {
"psr-4": {
@ -34,6 +41,14 @@
"phpDocumentor\\Reflection\\": ["tests/unit", "tests/integration"]
}
},
"config": {
"platform": {
"php":"7.4.0"
},
"allow-plugins": {
"phpstan/extension-installer": true
}
},
"extra": {
"branch-alias": {
"dev-master": "5.x-dev"

View File

@ -20,25 +20,25 @@ use Webmozart\Assert\Assert;
final class DocBlock
{
/** @var string The opening line for this docblock. */
private $summary;
private string $summary;
/** @var DocBlock\Description The actual description for this docblock. */
private $description;
private DocBlock\Description $description;
/** @var Tag[] An array containing all the tags in this docblock; except inline. */
private $tags = [];
private array $tags = [];
/** @var Types\Context|null Information about the context of this DocBlock. */
private $context;
private ?Types\Context $context = null;
/** @var Location|null Information about the location of this DocBlock. */
private $location;
private ?Location $location = null;
/** @var bool Is this DocBlock (the start of) a template? */
private $isTemplateStart;
private bool $isTemplateStart;
/** @var bool Does this DocBlock signify the end of a DocBlock template? */
private $isTemplateEnd;
private bool $isTemplateEnd;
/**
* @param DocBlock\Tag[] $tags

View File

@ -48,15 +48,14 @@ use function vsprintf;
* is mainly responsible for rendering.
*
* @see DescriptionFactory to create a new Description.
* @see Description\Formatter for the formatting of the body and tags.
* @see Tags\Formatter for the formatting of the body and tags.
*/
class Description
{
/** @var string */
private $bodyTemplate;
private string $bodyTemplate;
/** @var Tag[] */
private $tags;
private array $tags;
/**
* Initializes a Description with its body (template) and a listing of the tags used in the body template.
@ -93,6 +92,10 @@ class Description
*/
public function render(?Formatter $formatter = null): string
{
if ($this->tags === []) {
return vsprintf($this->bodyTemplate, []);
}
if ($formatter === null) {
$formatter = new PassthroughFormatter();
}

View File

@ -13,6 +13,7 @@ declare(strict_types=1);
namespace phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\Factory;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use phpDocumentor\Reflection\Utils;
@ -47,13 +48,12 @@ use const PREG_SPLIT_DELIM_CAPTURE;
*/
class DescriptionFactory
{
/** @var TagFactory */
private $tagFactory;
private Factory $tagFactory;
/**
* Initializes this factory with the means to construct (inline) tags.
*/
public function __construct(TagFactory $tagFactory)
public function __construct(Factory $tagFactory)
{
$this->tagFactory = $tagFactory;
}

View File

@ -31,11 +31,10 @@ use const DIRECTORY_SEPARATOR;
*/
class ExampleFinder
{
/** @var string */
private $sourceDirectory = '';
private string $sourceDirectory = '';
/** @var string[] */
private $exampleDirectories = [];
private array $exampleDirectories = [];
/**
* Attempts to find the example contents for the given descriptor.

View File

@ -29,21 +29,20 @@ use function wordwrap;
class Serializer
{
/** @var string The string to indent the comment with. */
protected $indentString = ' ';
protected string $indentString = ' ';
/** @var int The number of times the indent string is repeated. */
protected $indent = 0;
protected int $indent = 0;
/** @var bool Whether to indent the first line with the given indent amount and string. */
protected $isFirstLineIndented = true;
protected bool $isFirstLineIndented = true;
/** @var int|null The max length of a line. */
protected $lineLength;
protected ?int $lineLength = null;
/** @var Formatter A custom tag formatter. */
protected $tagFormatter;
/** @var string */
private $lineEnding;
protected Formatter $tagFormatter;
private string $lineEnding;
/**
* Create a Serializer instance.

View File

@ -17,6 +17,7 @@ use InvalidArgumentException;
use phpDocumentor\Reflection\DocBlock\Tags\Author;
use phpDocumentor\Reflection\DocBlock\Tags\Covers;
use phpDocumentor\Reflection\DocBlock\Tags\Deprecated;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\Factory;
use phpDocumentor\Reflection\DocBlock\Tags\Generic;
use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag;
use phpDocumentor\Reflection\DocBlock\Tags\Link as LinkTag;
@ -40,12 +41,15 @@ use ReflectionNamedType;
use ReflectionParameter;
use Webmozart\Assert\Assert;
use function array_key_exists;
use function array_merge;
use function array_slice;
use function call_user_func_array;
use function count;
use function get_class;
use function is_object;
use function preg_match;
use function sprintf;
use function strpos;
use function trim;
@ -72,10 +76,10 @@ final class StandardTagFactory implements TagFactory
public const REGEX_TAGNAME = '[\w\-\_\\\\:]+';
/**
* @var array<class-string<Tag>> An array with a tag as a key, and an
* @var array<class-string<Tag>|Factory> An array with a tag as a key, and an
* FQCN to a class that handles it as an array value.
*/
private $tagHandlerMappings = [
private array $tagHandlerMappings = [
'author' => Author::class,
'covers' => Covers::class,
'deprecated' => Deprecated::class,
@ -101,22 +105,21 @@ final class StandardTagFactory implements TagFactory
* @var array<class-string<Tag>> An array with a anotation s a key, and an
* FQCN to a class that handles it as an array value.
*/
private $annotationMappings = [];
private array $annotationMappings = [];
/**
* @var ReflectionParameter[][] a lazy-loading cache containing parameters
* for each tagHandler that has been used.
*/
private $tagHandlerParameterCache = [];
private array $tagHandlerParameterCache = [];
/** @var FqsenResolver */
private $fqsenResolver;
private FqsenResolver $fqsenResolver;
/**
* @var mixed[] an array representing a simple Service Locator where we can store parameters and
* services that can be inserted into the Factory Methods of Tag Handlers.
*/
private $serviceLocator = [];
private array $serviceLocator = [];
/**
* Initialize this tag factory with the means to resolve an FQSEN and optionally a list of tag handlers.
@ -162,18 +165,25 @@ final class StandardTagFactory implements TagFactory
$this->serviceLocator[$alias ?: get_class($service)] = $service;
}
public function registerTagHandler(string $tagName, string $handler): void
/** {@inheritDoc} */
public function registerTagHandler(string $tagName, $handler): void
{
Assert::stringNotEmpty($tagName);
Assert::classExists($handler);
Assert::implementsInterface($handler, Tag::class);
if (strpos($tagName, '\\') && $tagName[0] !== '\\') {
throw new InvalidArgumentException(
'A namespaced tag must have a leading backslash as it must be fully qualified'
);
}
if (is_object($handler)) {
Assert::isInstanceOf($handler, Factory::class);
$this->tagHandlerMappings[$tagName] = $handler;
return;
}
Assert::classExists($handler);
Assert::implementsInterface($handler, Tag::class);
$this->tagHandlerMappings[$tagName] = $handler;
}
@ -210,6 +220,10 @@ final class StandardTagFactory implements TagFactory
$this->getServiceLocatorWithDynamicParameters($context, $name, $body)
);
if (array_key_exists('tagLine', $arguments)) {
$arguments['tagLine'] = sprintf('@%s %s', $name, $body);
}
try {
$callable = [$handlerClassName, 'create'];
Assert::isCallable($callable);
@ -225,9 +239,9 @@ final class StandardTagFactory implements TagFactory
/**
* Determines the Fully Qualified Class Name of the Factory or Tag (containing a Factory Method `create`).
*
* @return class-string<Tag>
* @return class-string<Tag>|Factory
*/
private function findHandlerClassName(string $tagName, TypeContext $context): string
private function findHandlerClassName(string $tagName, TypeContext $context)
{
$handlerClassName = Generic::class;
if (isset($this->tagHandlerMappings[$tagName])) {
@ -268,18 +282,18 @@ final class StandardTagFactory implements TagFactory
}
}
if (isset($locator[$typeHint])) {
$arguments[] = $locator[$typeHint];
continue;
}
$parameterName = $parameter->getName();
if (isset($locator[$parameterName])) {
$arguments[] = $locator[$parameterName];
if (isset($locator[$typeHint])) {
$arguments[$parameterName] = $locator[$typeHint];
continue;
}
$arguments[] = null;
if (isset($locator[$parameterName])) {
$arguments[$parameterName] = $locator[$parameterName];
continue;
}
$arguments[$parameterName] = null;
}
return $arguments;
@ -289,12 +303,14 @@ final class StandardTagFactory implements TagFactory
* Retrieves a series of ReflectionParameter objects for the static 'create' method of the given
* tag handler class name.
*
* @param class-string $handlerClassName
* @param class-string|Factory $handler
*
* @return ReflectionParameter[]
*/
private function fetchParametersForHandlerFactoryMethod(string $handlerClassName): array
private function fetchParametersForHandlerFactoryMethod($handler): array
{
$handlerClassName = is_object($handler) ? get_class($handler) : $handler;
if (!isset($this->tagHandlerParameterCache[$handlerClassName])) {
$methodReflection = new ReflectionMethod($handlerClassName, 'create');
$this->tagHandlerParameterCache[$handlerClassName] = $methodReflection->getParameters();

View File

@ -14,9 +14,9 @@ declare(strict_types=1);
namespace phpDocumentor\Reflection\DocBlock;
use InvalidArgumentException;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\Factory;
interface TagFactory
interface TagFactory extends Factory
{
/**
* Adds a parameter to the service locator that can be injected in a tag's factory method.
@ -40,17 +40,6 @@ interface TagFactory
*/
public function addParameter(string $name, $value): void;
/**
* Factory method responsible for instantiating the correct sub type.
*
* @param string $tagLine The text for this tag, including description.
*
* @return Tag A new tag object.
*
* @throws InvalidArgumentException If an invalid tag line was presented.
*/
public function create(string $tagLine, ?TypeContext $context = null): Tag;
/**
* Registers a service with the Service Locator using the FQCN of the class or the alias, if provided.
*
@ -71,7 +60,7 @@ interface TagFactory
*
* @param string $tagName Name of tag to register a handler for. When registering a namespaced
* tag, the full name, along with a prefixing slash MUST be provided.
* @param class-string<Tag> $handler FQCN of handler.
* @param class-string<Tag>|Factory $handler FQCN of handler.
*
* @throws InvalidArgumentException If the tag name is not a string.
* @throws InvalidArgumentException If the tag name is namespaced (contains backslashes) but
@ -80,5 +69,5 @@ interface TagFactory
* @throws InvalidArgumentException If the handler is not an existing class.
* @throws InvalidArgumentException If the handler does not implement the {@see Tag} interface.
*/
public function registerTagHandler(string $tagName, string $handler): void;
public function registerTagHandler(string $tagName, $handler): void;
}

View File

@ -27,13 +27,13 @@ use const FILTER_VALIDATE_EMAIL;
final class Author extends BaseTag implements Factory\StaticMethod
{
/** @var string register that this is the author tag. */
protected $name = 'author';
protected string $name = 'author';
/** @var string The name of the author */
private $authorName;
private string $authorName;
/** @var string The email of the author */
private $authorEmail;
private string $authorEmail;
/**
* Initializes this tag with the author name and e-mail.

View File

@ -22,10 +22,10 @@ use phpDocumentor\Reflection\DocBlock\Description;
abstract class BaseTag implements DocBlock\Tag
{
/** @var string Name of the tag */
protected $name = '';
protected string $name = '';
/** @var Description|null Description of the tag. */
protected $description;
protected ?Description $description = null;
/**
* Gets the name of this tag.

View File

@ -29,11 +29,9 @@ use function explode;
*/
final class Covers extends BaseTag implements Factory\StaticMethod
{
/** @var string */
protected $name = 'covers';
protected string $name = 'covers';
/** @var Fqsen */
private $refers;
private Fqsen $refers;
/**
* Initializes this tag.

View File

@ -25,8 +25,7 @@ use function preg_match;
*/
final class Deprecated extends BaseTag implements Factory\StaticMethod
{
/** @var string */
protected $name = 'deprecated';
protected string $name = 'deprecated';
/**
* PCRE regular expression matching a version vector.
@ -45,7 +44,7 @@ final class Deprecated extends BaseTag implements Factory\StaticMethod
)';
/** @var string|null The version vector. */
private $version;
private ?string $version = null;
public function __construct(?string $version = null, ?Description $description = null)
{

View File

@ -29,22 +29,19 @@ use function trim;
final class Example implements Tag, Factory\StaticMethod
{
/** @var string Path to a file to use as an example. May also be an absolute URI. */
private $filePath;
private string $filePath;
/**
* @var bool Whether the file path component represents an URI. This determines how the file portion
* appears at {@link getContent()}.
*/
private $isURI;
private bool $isURI;
/** @var int */
private $startingLine;
private int $startingLine;
/** @var int */
private $lineCount;
private int $lineCount;
/** @var string|null */
private $content;
private ?string $content = null;
public function __construct(
string $filePath,

View File

@ -0,0 +1,122 @@
<?php
/*
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link http://phpdoc.org
*
*/
declare(strict_types=1);
namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag;
use phpDocumentor\Reflection\Types\Context as TypeContext;
use PHPStan\PhpDocParser\Lexer\Lexer;
use PHPStan\PhpDocParser\Parser\ConstExprParser;
use PHPStan\PhpDocParser\Parser\PhpDocParser;
use PHPStan\PhpDocParser\Parser\TokenIterator;
use PHPStan\PhpDocParser\Parser\TypeParser;
use RuntimeException;
use function ltrim;
use function property_exists;
use function rtrim;
/**
* Factory class creating tags using phpstan's parser
*
* This class uses {@see PHPStanFactory} implementations to create tags
* from the ast of the phpstan docblock parser.
*
* @internal This class is not part of the BC promise of this library.
*/
class AbstractPHPStanFactory implements Factory
{
private PhpDocParser $parser;
private Lexer $lexer;
/** @var PHPStanFactory[] */
private array $factories;
public function __construct(PHPStanFactory ...$factories)
{
$this->lexer = new Lexer(true);
$constParser = new ConstExprParser(true, true, ['lines' => true, 'indexes' => true]);
$this->parser = new PhpDocParser(
new TypeParser($constParser, true, ['lines' => true, 'indexes' => true]),
$constParser,
true,
true,
['lines' => true, 'indexes' => true],
true
);
$this->factories = $factories;
}
public function create(string $tagLine, ?TypeContext $context = null): Tag
{
$tokens = $this->tokenizeLine($tagLine);
$ast = $this->parser->parseTag($tokens);
if (property_exists($ast->value, 'description') === true) {
$ast->value->setAttribute(
'description',
$ast->value->description . $tokens->joinUntil(Lexer::TOKEN_END)
);
}
if ($context === null) {
$context = new TypeContext('');
}
try {
foreach ($this->factories as $factory) {
if ($factory->supports($ast, $context)) {
return $factory->create($ast, $context);
}
}
} catch (RuntimeException $e) {
return InvalidTag::create((string) $ast->value, 'method')->withError($e);
}
return InvalidTag::create(
(string) $ast->value,
$ast->name
);
}
/**
* Solve the issue with the lexer not tokenizing the line correctly
*
* This method is a workaround for the lexer that includes newline tokens with spaces. For
* phpstan this isn't an issue, as it doesn't do a lot of things with the indentation of descriptions.
* But for us is important to keep the indentation of the descriptions, so we need to fix the lexer output.
*/
private function tokenizeLine(string $tagLine): TokenIterator
{
$tokens = $this->lexer->tokenize($tagLine);
$fixed = [];
foreach ($tokens as $token) {
if (($token[1] === Lexer::TOKEN_PHPDOC_EOL) && rtrim($token[0], " \t") !== $token[0]) {
$fixed[] = [
rtrim($token[Lexer::VALUE_OFFSET], " \t"),
Lexer::TOKEN_PHPDOC_EOL,
$token[2] ?? null,
];
$fixed[] = [
ltrim($token[Lexer::VALUE_OFFSET], "\n\r"),
Lexer::TOKEN_HORIZONTAL_WS,
($token[2] ?? null) + 1,
];
continue;
}
$fixed[] = $token;
}
return new TokenIterator($fixed);
}
}

View File

@ -0,0 +1,41 @@
<?php
/*
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link http://phpdoc.org
*
*/
declare(strict_types=1);
/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link http://phpdoc.org
*/
namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
use InvalidArgumentException;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\Types\Context as TypeContext;
interface Factory
{
/**
* Factory method responsible for instantiating the correct sub type.
*
* @param string $tagLine The text for this tag, including description.
*
* @return Tag A new tag object.
*
* @throws InvalidArgumentException If an invalid tag line was presented.
*/
public function create(string $tagLine, ?TypeContext $context = null): Tag;
}

View File

@ -0,0 +1,81 @@
<?php
declare(strict_types=1);
namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\Method;
use phpDocumentor\Reflection\DocBlock\Tags\MethodParameter;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use phpDocumentor\Reflection\Types\Mixed_;
use phpDocumentor\Reflection\Types\Void_;
use PHPStan\PhpDocParser\Ast\PhpDoc\MethodTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\MethodTagValueParameterNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use Webmozart\Assert\Assert;
use function array_map;
use function trim;
/**
* @internal This class is not part of the BC promise of this library.
*/
final class MethodFactory implements PHPStanFactory
{
private DescriptionFactory $descriptionFactory;
private TypeResolver $typeResolver;
public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
{
$this->descriptionFactory = $descriptionFactory;
$this->typeResolver = $typeResolver;
}
public function create(PhpDocTagNode $node, Context $context): Tag
{
$tagValue = $node->value;
Assert::isInstanceOf($tagValue, MethodTagValueNode::class);
return new Method(
$tagValue->methodName,
[],
$this->createReturnType($tagValue, $context),
$tagValue->isStatic,
$this->descriptionFactory->create($tagValue->description, $context),
false,
array_map(
function (MethodTagValueParameterNode $param) use ($context) {
return new MethodParameter(
trim($param->parameterName, '$'),
$param->type === null ? new Mixed_() : $this->typeResolver->createType(
$param->type,
$context
),
$param->isReference,
$param->isVariadic,
(string) $param->defaultValue
);
},
$tagValue->parameters
),
);
}
public function supports(PhpDocTagNode $node, Context $context): bool
{
return $node->value instanceof MethodTagValueNode;
}
private function createReturnType(MethodTagValueNode $tagValue, Context $context): Type
{
if ($tagValue->returnType === null) {
return new Void_();
}
return $this->typeResolver->createType($tagValue->returnType, $context);
}
}

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
interface PHPStanFactory
{
public function create(PhpDocTagNode $node, Context $context): Tag;
public function supports(PhpDocTagNode $node, Context $context): bool;
}

View File

@ -0,0 +1,92 @@
<?php
declare(strict_types=1);
namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
use Doctrine\Deprecations\Deprecation;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag;
use phpDocumentor\Reflection\DocBlock\Tags\Param;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\InvalidTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\TypelessParamTagValueNode;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\PhpDocParser\Ast\Type\OffsetAccessTypeNode;
use Webmozart\Assert\Assert;
use function is_string;
use function sprintf;
use function trim;
/**
* @internal This class is not part of the BC promise of this library.
*/
final class ParamFactory implements PHPStanFactory
{
private DescriptionFactory $descriptionFactory;
private TypeResolver $typeResolver;
public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
{
$this->descriptionFactory = $descriptionFactory;
$this->typeResolver = $typeResolver;
}
public function create(PhpDocTagNode $node, Context $context): Tag
{
$tagValue = $node->value;
if ($tagValue instanceof InvalidTagValueNode) {
Deprecation::trigger(
'phpdocumentor/reflection-docblock',
'https://github.com/phpDocumentor/ReflectionDocBlock/issues/362',
sprintf(
'Param tag value "%s" is invalid, falling back to legacy parsing. Please update your docblocks.',
$tagValue->value
)
);
return Param::create($tagValue->value, $this->typeResolver, $this->descriptionFactory, $context);
}
Assert::isInstanceOfAny(
$tagValue,
[
ParamTagValueNode::class,
TypelessParamTagValueNode::class,
]
);
if (($tagValue->type ?? null) instanceof OffsetAccessTypeNode) {
return InvalidTag::create(
(string) $tagValue,
'param'
);
}
$description = $tagValue->getAttribute('description');
if (is_string($description) === false) {
$description = $tagValue->description;
}
return new Param(
trim($tagValue->parameterName, '$'),
$this->typeResolver->createType($tagValue->type ?? new IdentifierTypeNode('mixed'), $context),
$tagValue->isVariadic,
$this->descriptionFactory->create($description, $context),
$tagValue->isReference
);
}
public function supports(PhpDocTagNode $node, Context $context): bool
{
return $node->value instanceof ParamTagValueNode
|| $node->value instanceof TypelessParamTagValueNode
|| $node->name === '@param';
}
}

View File

@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\Property;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PropertyTagValueNode;
use Webmozart\Assert\Assert;
use function is_string;
use function trim;
/**
* @internal This class is not part of the BC promise of this library.
*/
final class PropertyFactory implements PHPStanFactory
{
private DescriptionFactory $descriptionFactory;
private TypeResolver $typeResolver;
public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
{
$this->descriptionFactory = $descriptionFactory;
$this->typeResolver = $typeResolver;
}
public function create(PhpDocTagNode $node, Context $context): Tag
{
$tagValue = $node->value;
Assert::isInstanceOf($tagValue, PropertyTagValueNode::class);
$description = $tagValue->getAttribute('description');
if (is_string($description) === false) {
$description = $tagValue->description;
}
return new Property(
trim($tagValue->propertyName, '$'),
$this->typeResolver->createType($tagValue->type, $context),
$this->descriptionFactory->create($description, $context)
);
}
public function supports(PhpDocTagNode $node, Context $context): bool
{
return $node->value instanceof PropertyTagValueNode && $node->name === '@property';
}
}

View File

@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\PropertyRead;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PropertyTagValueNode;
use Webmozart\Assert\Assert;
use function is_string;
use function trim;
/**
* @internal This class is not part of the BC promise of this library.
*/
final class PropertyReadFactory implements PHPStanFactory
{
private DescriptionFactory $descriptionFactory;
private TypeResolver $typeResolver;
public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
{
$this->typeResolver = $typeResolver;
$this->descriptionFactory = $descriptionFactory;
}
public function create(PhpDocTagNode $node, Context $context): Tag
{
$tagValue = $node->value;
Assert::isInstanceOf($tagValue, PropertyTagValueNode::class);
$description = $tagValue->getAttribute('description');
if (is_string($description) === false) {
$description = $tagValue->description;
}
return new PropertyRead(
trim($tagValue->propertyName, '$'),
$this->typeResolver->createType($tagValue->type, $context),
$this->descriptionFactory->create($description, $context)
);
}
public function supports(PhpDocTagNode $node, Context $context): bool
{
return $node->value instanceof PropertyTagValueNode && $node->name === '@property-read';
}
}

View File

@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\PropertyWrite;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PropertyTagValueNode;
use Webmozart\Assert\Assert;
use function is_string;
use function trim;
/**
* @internal This class is not part of the BC promise of this library.
*/
final class PropertyWriteFactory implements PHPStanFactory
{
private DescriptionFactory $descriptionFactory;
private TypeResolver $typeResolver;
public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
{
$this->descriptionFactory = $descriptionFactory;
$this->typeResolver = $typeResolver;
}
public function create(PhpDocTagNode $node, Context $context): Tag
{
$tagValue = $node->value;
Assert::isInstanceOf($tagValue, PropertyTagValueNode::class);
$description = $tagValue->getAttribute('description');
if (is_string($description) === false) {
$description = $tagValue->description;
}
return new PropertyWrite(
trim($tagValue->propertyName, '$'),
$this->typeResolver->createType($tagValue->type, $context),
$this->descriptionFactory->create($description, $context)
);
}
public function supports(PhpDocTagNode $node, Context $context): bool
{
return $node->value instanceof PropertyTagValueNode && $node->name === '@property-write';
}
}

View File

@ -0,0 +1,52 @@
<?php
declare(strict_types=1);
namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\Return_;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
use Webmozart\Assert\Assert;
use function is_string;
/**
* @internal This class is not part of the BC promise of this library.
*/
final class ReturnFactory implements PHPStanFactory
{
private DescriptionFactory $descriptionFactory;
private TypeResolver $typeResolver;
public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
{
$this->descriptionFactory = $descriptionFactory;
$this->typeResolver = $typeResolver;
}
public function create(PhpDocTagNode $node, Context $context): Tag
{
$tagValue = $node->value;
Assert::isInstanceOf($tagValue, ReturnTagValueNode::class);
$description = $tagValue->getAttribute('description');
if (is_string($description) === false) {
$description = $tagValue->description;
}
return new Return_(
$this->typeResolver->createType($tagValue->type, $context),
$this->descriptionFactory->create($description, $context)
);
}
public function supports(PhpDocTagNode $node, Context $context): bool
{
return $node->value instanceof ReturnTagValueNode;
}
}

View File

@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\Var_;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
use Webmozart\Assert\Assert;
use function is_string;
use function trim;
/**
* @internal This class is not part of the BC promise of this library.
*/
final class VarFactory implements PHPStanFactory
{
private DescriptionFactory $descriptionFactory;
private TypeResolver $typeResolver;
public function __construct(TypeResolver $typeResolver, DescriptionFactory $descriptionFactory)
{
$this->descriptionFactory = $descriptionFactory;
$this->typeResolver = $typeResolver;
}
public function create(PhpDocTagNode $node, Context $context): Tag
{
$tagValue = $node->value;
Assert::isInstanceOf($tagValue, VarTagValueNode::class);
$description = $tagValue->getAttribute('description');
if (is_string($description) === false) {
$description = $tagValue->description;
}
return new Var_(
trim($tagValue->variableName, '$'),
$this->typeResolver->createType($tagValue->type, $context),
$this->descriptionFactory->create($description, $context)
);
}
public function supports(PhpDocTagNode $node, Context $context): bool
{
return $node->value instanceof VarTagValueNode;
}
}

View File

@ -23,7 +23,7 @@ use function strlen;
class AlignFormatter implements Formatter
{
/** @var int The maximum tag name length. */
protected $maxLen = 0;
protected int $maxLen = 0;
/**
* @param Tag[] $tags All tags that should later be aligned with the formatter.

View File

@ -32,14 +32,11 @@ use function sprintf;
*/
final class InvalidTag implements Tag
{
/** @var string */
private $name;
private string $name;
/** @var string */
private $body;
private string $body;
/** @var Throwable|null */
private $throwable;
private ?Throwable $throwable = null;
private function __construct(string $name, string $body)
{

View File

@ -24,11 +24,9 @@ use Webmozart\Assert\Assert;
*/
final class Link extends BaseTag implements Factory\StaticMethod
{
/** @var string */
protected $name = 'link';
protected string $name = 'link';
/** @var string */
private $link;
private string $link;
/**
* Initializes a link to a URL.

View File

@ -24,6 +24,7 @@ use phpDocumentor\Reflection\Types\Void_;
use Webmozart\Assert\Assert;
use function array_keys;
use function array_map;
use function explode;
use function implode;
use function is_string;
@ -31,34 +32,33 @@ use function preg_match;
use function sort;
use function strpos;
use function substr;
use function trigger_error;
use function trim;
use function var_export;
use const E_USER_DEPRECATED;
/**
* Reflection class for an {@}method in a Docblock.
*/
final class Method extends BaseTag implements Factory\StaticMethod
{
/** @var string */
protected $name = 'method';
protected string $name = 'method';
/** @var string */
private $methodName;
private string $methodName;
/**
* @phpstan-var array<int, array{name: string, type: Type}>
* @var array<int, array<string, Type|string>>
*/
private $arguments;
private bool $isStatic;
/** @var bool */
private $isStatic;
private Type $returnType;
/** @var Type */
private $returnType;
private bool $returnsReference;
/** @var MethodParameter[] */
private array $parameters;
/**
* @param array<int, array<string, Type|string>> $arguments
* @param MethodParameter[] $parameters
* @phpstan-param array<int, array{name: string, type: Type}|string> $arguments
*/
public function __construct(
@ -66,7 +66,9 @@ final class Method extends BaseTag implements Factory\StaticMethod
array $arguments = [],
?Type $returnType = null,
bool $static = false,
?Description $description = null
?Description $description = null,
bool $returnsReference = false,
?array $parameters = null
) {
Assert::stringNotEmpty($methodName);
@ -74,19 +76,31 @@ final class Method extends BaseTag implements Factory\StaticMethod
$returnType = new Void_();
}
$this->methodName = $methodName;
$this->arguments = $this->filterArguments($arguments);
$this->returnType = $returnType;
$this->isStatic = $static;
$this->description = $description;
$arguments = $this->filterArguments($arguments);
$this->methodName = $methodName;
$this->returnType = $returnType;
$this->isStatic = $static;
$this->description = $description;
$this->returnsReference = $returnsReference;
$this->parameters = $parameters ?? $this->fromLegacyArguments($arguments);
}
/**
* @deprecated Create using static factory is deprecated,
* this method should not be called directly by library consumers
*/
public static function create(
string $body,
?TypeResolver $typeResolver = null,
?DescriptionFactory $descriptionFactory = null,
?TypeContext $context = null
): ?self {
trigger_error(
'Create using static factory is deprecated, this method should not be called directly
by library consumers',
E_USER_DEPRECATED
);
Assert::stringNotEmpty($body);
Assert::notNull($typeResolver);
Assert::notNull($descriptionFactory);
@ -95,11 +109,13 @@ final class Method extends BaseTag implements Factory\StaticMethod
// 2. optionally the keyword "static" followed by whitespace
// 3. optionally a word with underscores followed by whitespace : as
// type for the return value
// 4. then optionally a word with underscores followed by () and
// 4. optionally an ampersand followed or not by whitespace : as
// a reference
// 5. then optionally a word with underscores followed by () and
// whitespace : as method name as used by phpDocumentor
// 5. then a word with underscores, followed by ( and any character
// 6. then a word with underscores, followed by ( and any character
// until a ) and whitespace : as method name with signature
// 6. any remaining text : as description
// 7. any remaining text : as description
if (
!preg_match(
'/^
@ -122,6 +138,11 @@ final class Method extends BaseTag implements Factory\StaticMethod
)
\s+
)?
# Returns reference
(?:
(&)
\s*
)?
# Method name
([\w_]+)
# Arguments
@ -139,7 +160,7 @@ final class Method extends BaseTag implements Factory\StaticMethod
return null;
}
[, $static, $returnType, $methodName, $argumentLines, $description] = $matches;
[, $static, $returnType, $returnsReference, $methodName, $argumentLines, $description] = $matches;
$static = $static === 'static';
@ -147,6 +168,8 @@ final class Method extends BaseTag implements Factory\StaticMethod
$returnType = 'void';
}
$returnsReference = $returnsReference === '&';
$returnType = $typeResolver->resolve($returnType, $context);
$description = $descriptionFactory->create($description, $context);
@ -172,7 +195,14 @@ final class Method extends BaseTag implements Factory\StaticMethod
}
}
return new static($methodName, $arguments, $returnType, $static, $description);
return new static(
$methodName,
$arguments,
$returnType,
$static,
$description,
$returnsReference
);
}
/**
@ -184,12 +214,27 @@ final class Method extends BaseTag implements Factory\StaticMethod
}
/**
* @deprecated Method deprecated, use {@see self::getParameters()}
*
* @return array<int, array<string, Type|string>>
* @phpstan-return array<int, array{name: string, type: Type}>
*/
public function getArguments(): array
{
return $this->arguments;
trigger_error('Method deprecated, use ::getParameters()', E_USER_DEPRECATED);
return array_map(
static function (MethodParameter $methodParameter) {
return ['name' => $methodParameter->getName(), 'type' => $methodParameter->getType()];
},
$this->parameters
);
}
/** @return MethodParameter[] */
public function getParameters(): array
{
return $this->parameters;
}
/**
@ -207,11 +252,19 @@ final class Method extends BaseTag implements Factory\StaticMethod
return $this->returnType;
}
public function returnsReference(): bool
{
return $this->returnsReference;
}
public function __toString(): string
{
$arguments = [];
foreach ($this->arguments as $argument) {
$arguments[] = $argument['type'] . ' $' . $argument['name'];
foreach ($this->parameters as $parameter) {
$arguments[] = $parameter->getType() . ' ' .
($parameter->isReference() ? '&' : '') .
($parameter->isVariadic() ? '...' : '') .
'$' . $parameter->getName();
}
$argumentStr = '(' . implode(', ', $arguments) . ')';
@ -228,9 +281,11 @@ final class Method extends BaseTag implements Factory\StaticMethod
$methodName = $this->methodName;
$reference = $this->returnsReference ? '&' : '';
return $static
. ($returnType !== '' ? ($static !== '' ? ' ' : '') . $returnType : '')
. ($methodName !== '' ? ($static !== '' || $returnType !== '' ? ' ' : '') . $methodName : '')
. ($methodName !== '' ? ($static !== '' || $returnType !== '' ? ' ' : '') . $reference . $methodName : '')
. $argumentStr
. ($description !== '' ? ' ' . $description : '');
}
@ -276,4 +331,28 @@ final class Method extends BaseTag implements Factory\StaticMethod
return $argument;
}
/**
* @param array{name: string, type: Type} $arguments
* @phpstan-param array<int, array{name: string, type: Type}> $arguments
*
* @return MethodParameter[]
*/
private function fromLegacyArguments(array $arguments): array
{
trigger_error(
'Create method parameters via legacy format is deprecated add parameters via the constructor',
E_USER_DEPRECATED
);
return array_map(
static function ($arg) {
return new MethodParameter(
$arg['name'],
$arg['type']
);
},
$arguments
);
}
}

View File

@ -0,0 +1,67 @@
<?php
/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link http://phpdoc.org
*/
declare(strict_types=1);
namespace phpDocumentor\Reflection\DocBlock\Tags;
use phpDocumentor\Reflection\Type;
final class MethodParameter
{
private Type $type;
private bool $isReference;
private bool $isVariadic;
private string $name;
private ?string $defaultValue = null;
public function __construct(
string $name,
Type $type,
bool $isReference = false,
bool $isVariadic = false,
?string $defaultValue = null
) {
$this->type = $type;
$this->isReference = $isReference;
$this->isVariadic = $isVariadic;
$this->name = $name;
$this->defaultValue = $defaultValue;
}
public function getName(): string
{
return $this->name;
}
public function getType(): Type
{
return $this->type;
}
public function isReference(): bool
{
return $this->isReference;
}
public function isVariadic(): bool
{
return $this->isVariadic;
}
public function getDefaultValue(): ?string
{
return $this->defaultValue;
}
}

View File

@ -13,6 +13,7 @@ declare(strict_types=1);
namespace phpDocumentor\Reflection\DocBlock\Tags;
use Doctrine\Deprecations\Deprecation;
use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Type;
@ -34,14 +35,13 @@ use const PREG_SPLIT_DELIM_CAPTURE;
*/
final class Param extends TagWithType implements Factory\StaticMethod
{
/** @var string|null */
private $variableName;
private ?string $variableName = null;
/** @var bool determines whether this is a variadic argument */
private $isVariadic;
private bool $isVariadic;
/** @var bool determines whether this is passed by reference */
private $isReference;
private bool $isReference;
public function __construct(
?string $variableName,
@ -58,12 +58,23 @@ final class Param extends TagWithType implements Factory\StaticMethod
$this->isReference = $isReference;
}
/**
* @deprecated Create using static factory is deprecated,
* this method should not be called directly by library consumers
*/
public static function create(
string $body,
?TypeResolver $typeResolver = null,
?DescriptionFactory $descriptionFactory = null,
?TypeContext $context = null
): self {
Deprecation::triggerIfCalledFromOutside(
'phpdocumentor/reflection-docblock',
'https://github.com/phpDocumentor/ReflectionDocBlock/issues/361',
'Create using static factory is deprecated, this method should not be called directly
by library consumers',
);
Assert::stringNotEmpty($body);
Assert::notNull($typeResolver);
Assert::notNull($descriptionFactory);

View File

@ -13,6 +13,7 @@ declare(strict_types=1);
namespace phpDocumentor\Reflection\DocBlock\Tags;
use Doctrine\Deprecations\Deprecation;
use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Type;
@ -34,8 +35,7 @@ use const PREG_SPLIT_DELIM_CAPTURE;
*/
final class Property extends TagWithType implements Factory\StaticMethod
{
/** @var string|null */
protected $variableName;
protected ?string $variableName = null;
public function __construct(?string $variableName, ?Type $type = null, ?Description $description = null)
{
@ -47,12 +47,23 @@ final class Property extends TagWithType implements Factory\StaticMethod
$this->description = $description;
}
/**
* @deprecated Create using static factory is deprecated,
* this method should not be called directly by library consumers
*/
public static function create(
string $body,
?TypeResolver $typeResolver = null,
?DescriptionFactory $descriptionFactory = null,
?TypeContext $context = null
): self {
Deprecation::triggerIfCalledFromOutside(
'phpdocumentor/reflection-docblock',
'https://github.com/phpDocumentor/ReflectionDocBlock/issues/361',
'Create using static factory is deprecated, this method should not be called directly
by library consumers',
);
Assert::stringNotEmpty($body);
Assert::notNull($typeResolver);
Assert::notNull($descriptionFactory);

View File

@ -13,6 +13,7 @@ declare(strict_types=1);
namespace phpDocumentor\Reflection\DocBlock\Tags;
use Doctrine\Deprecations\Deprecation;
use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Type;
@ -34,8 +35,7 @@ use const PREG_SPLIT_DELIM_CAPTURE;
*/
final class PropertyRead extends TagWithType implements Factory\StaticMethod
{
/** @var string|null */
protected $variableName;
protected ?string $variableName = null;
public function __construct(?string $variableName, ?Type $type = null, ?Description $description = null)
{
@ -47,12 +47,23 @@ final class PropertyRead extends TagWithType implements Factory\StaticMethod
$this->description = $description;
}
/**
* @deprecated Create using static factory is deprecated,
* this method should not be called directly by library consumers
*/
public static function create(
string $body,
?TypeResolver $typeResolver = null,
?DescriptionFactory $descriptionFactory = null,
?TypeContext $context = null
): self {
Deprecation::triggerIfCalledFromOutside(
'phpdocumentor/reflection-docblock',
'https://github.com/phpDocumentor/ReflectionDocBlock/issues/361',
'Create using static factory is deprecated, this method should not be called directly
by library consumers',
);
Assert::stringNotEmpty($body);
Assert::notNull($typeResolver);
Assert::notNull($descriptionFactory);

View File

@ -13,6 +13,7 @@ declare(strict_types=1);
namespace phpDocumentor\Reflection\DocBlock\Tags;
use Doctrine\Deprecations\Deprecation;
use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Type;
@ -34,8 +35,7 @@ use const PREG_SPLIT_DELIM_CAPTURE;
*/
final class PropertyWrite extends TagWithType implements Factory\StaticMethod
{
/** @var string */
protected $variableName;
protected string $variableName;
public function __construct(?string $variableName, ?Type $type = null, ?Description $description = null)
{
@ -47,12 +47,23 @@ final class PropertyWrite extends TagWithType implements Factory\StaticMethod
$this->description = $description;
}
/**
* @deprecated Create using static factory is deprecated,
* this method should not be called directly by library consumers
*/
public static function create(
string $body,
?TypeResolver $typeResolver = null,
?DescriptionFactory $descriptionFactory = null,
?TypeContext $context = null
): self {
Deprecation::triggerIfCalledFromOutside(
'phpdocumentor/reflection-docblock',
'https://github.com/phpDocumentor/ReflectionDocBlock/issues/361',
'Create using static factory is deprecated, this method should not be called directly
by library consumers',
);
Assert::stringNotEmpty($body);
Assert::notNull($typeResolver);
Assert::notNull($descriptionFactory);

View File

@ -20,8 +20,7 @@ use phpDocumentor\Reflection\Fqsen as RealFqsen;
*/
final class Fqsen implements Reference
{
/** @var RealFqsen */
private $fqsen;
private RealFqsen $fqsen;
public function __construct(RealFqsen $fqsen)
{

View File

@ -20,8 +20,7 @@ use Webmozart\Assert\Assert;
*/
final class Url implements Reference
{
/** @var string */
private $uri;
private string $uri;
public function __construct(string $uri)
{

View File

@ -13,6 +13,7 @@ declare(strict_types=1);
namespace phpDocumentor\Reflection\DocBlock\Tags;
use Doctrine\Deprecations\Deprecation;
use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Type;
@ -32,12 +33,23 @@ final class Return_ extends TagWithType implements Factory\StaticMethod
$this->description = $description;
}
/**
* @deprecated Create using static factory is deprecated,
* this method should not be called directly by library consumers
*/
public static function create(
string $body,
?TypeResolver $typeResolver = null,
?DescriptionFactory $descriptionFactory = null,
?TypeContext $context = null
): self {
Deprecation::triggerIfCalledFromOutside(
'phpdocumentor/reflection-docblock',
'https://github.com/phpDocumentor/ReflectionDocBlock/issues/361',
'Create using static factory is deprecated, this method should not be called directly
by library consumers',
);
Assert::notNull($typeResolver);
Assert::notNull($descriptionFactory);

View File

@ -33,11 +33,9 @@ use function preg_match;
*/
final class See extends BaseTag implements Factory\StaticMethod
{
/** @var string */
protected $name = 'see';
protected string $name = 'see';
/** @var Reference */
protected $refers;
protected Reference $refers;
/**
* Initializes this tag.

View File

@ -25,8 +25,7 @@ use function preg_match;
*/
final class Since extends BaseTag implements Factory\StaticMethod
{
/** @var string */
protected $name = 'since';
protected string $name = 'since';
/**
* PCRE regular expression matching a version vector.
@ -45,7 +44,7 @@ final class Since extends BaseTag implements Factory\StaticMethod
)';
/** @var string|null The version vector. */
private $version;
private ?string $version = null;
public function __construct(?string $version = null, ?Description $description = null)
{

View File

@ -25,14 +25,13 @@ use function preg_match;
*/
final class Source extends BaseTag implements Factory\StaticMethod
{
/** @var string */
protected $name = 'source';
protected string $name = 'source';
/** @var int The starting line, relative to the structural element's location. */
private $startingLine;
private int $startingLine;
/** @var int|null The number of lines, relative to the starting line. NULL means "to the end". */
private $lineCount;
private ?int $lineCount = null;
/**
* @param int|string $startingLine should be a to int convertible value

View File

@ -13,9 +13,11 @@ declare(strict_types=1);
namespace phpDocumentor\Reflection\DocBlock\Tags;
use InvalidArgumentException;
use phpDocumentor\Reflection\Type;
use function in_array;
use function sprintf;
use function strlen;
use function substr;
use function trim;
@ -23,7 +25,7 @@ use function trim;
abstract class TagWithType extends BaseTag
{
/** @var ?Type */
protected $type;
protected ?Type $type = null;
/**
* Returns the type section of the variable.
@ -59,6 +61,12 @@ abstract class TagWithType extends BaseTag
}
}
if ($nestingLevel < 0 || $nestingLevel > 0) {
throw new InvalidArgumentException(
sprintf('Could not find type in %s, please check for malformed notations', $body)
);
}
$description = trim(substr($body, strlen($type)));
return [$type, $description];

View File

@ -29,11 +29,9 @@ use function explode;
*/
final class Uses extends BaseTag implements Factory\StaticMethod
{
/** @var string */
protected $name = 'uses';
protected string $name = 'uses';
/** @var Fqsen */
protected $refers;
protected Fqsen $refers;
/**
* Initializes this tag.

View File

@ -13,6 +13,7 @@ declare(strict_types=1);
namespace phpDocumentor\Reflection\DocBlock\Tags;
use Doctrine\Deprecations\Deprecation;
use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\Type;
@ -34,8 +35,7 @@ use const PREG_SPLIT_DELIM_CAPTURE;
*/
final class Var_ extends TagWithType implements Factory\StaticMethod
{
/** @var string|null */
protected $variableName = '';
protected ?string $variableName = '';
public function __construct(?string $variableName, ?Type $type = null, ?Description $description = null)
{
@ -47,12 +47,22 @@ final class Var_ extends TagWithType implements Factory\StaticMethod
$this->description = $description;
}
/**
* @deprecated Create using static factory is deprecated,
* this method should not be called directly by library consumers
*/
public static function create(
string $body,
?TypeResolver $typeResolver = null,
?DescriptionFactory $descriptionFactory = null,
?TypeContext $context = null
): self {
Deprecation::triggerIfCalledFromOutside(
'phpdocumentor/reflection-docblock',
'https://github.com/phpDocumentor/ReflectionDocBlock/issues/361',
'Create using static factory is deprecated, this method should not be called directly
by library consumers',
);
Assert::stringNotEmpty($body);
Assert::notNull($typeResolver);
Assert::notNull($descriptionFactory);

View File

@ -25,8 +25,7 @@ use function preg_match;
*/
final class Version extends BaseTag implements Factory\StaticMethod
{
/** @var string */
protected $name = 'version';
protected string $name = 'version';
/**
* PCRE regular expression matching a version vector.
@ -45,7 +44,7 @@ final class Version extends BaseTag implements Factory\StaticMethod
)';
/** @var string|null The version vector. */
private $version;
private ?string $version = null;
public function __construct(?string $version = null, ?Description $description = null)
{

View File

@ -19,6 +19,15 @@ use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
use phpDocumentor\Reflection\DocBlock\StandardTagFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\TagFactory;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\AbstractPHPStanFactory;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\Factory;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\MethodFactory;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\ParamFactory;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\PropertyFactory;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\PropertyReadFactory;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\PropertyWriteFactory;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\ReturnFactory;
use phpDocumentor\Reflection\DocBlock\Tags\Factory\VarFactory;
use Webmozart\Assert\Assert;
use function array_shift;
@ -35,11 +44,9 @@ use function trim;
final class DocBlockFactory implements DocBlockFactoryInterface
{
/** @var DocBlock\DescriptionFactory */
private $descriptionFactory;
private DocBlock\DescriptionFactory $descriptionFactory;
/** @var DocBlock\TagFactory */
private $tagFactory;
private TagFactory $tagFactory;
/**
* Initializes this factory with the required subcontractors.
@ -47,22 +54,40 @@ final class DocBlockFactory implements DocBlockFactoryInterface
public function __construct(DescriptionFactory $descriptionFactory, TagFactory $tagFactory)
{
$this->descriptionFactory = $descriptionFactory;
$this->tagFactory = $tagFactory;
$this->tagFactory = $tagFactory;
}
/**
* Factory method for easy instantiation.
*
* @param array<string, class-string<Tag>> $additionalTags
* @param array<string, class-string<Tag>|Factory> $additionalTags
*/
public static function createInstance(array $additionalTags = []): self
public static function createInstance(array $additionalTags = []): DocBlockFactoryInterface
{
$fqsenResolver = new FqsenResolver();
$tagFactory = new StandardTagFactory($fqsenResolver);
$fqsenResolver = new FqsenResolver();
$tagFactory = new StandardTagFactory($fqsenResolver);
$descriptionFactory = new DescriptionFactory($tagFactory);
$typeResolver = new TypeResolver($fqsenResolver);
$phpstanTagFactory = new AbstractPHPStanFactory(
new ParamFactory($typeResolver, $descriptionFactory),
new VarFactory($typeResolver, $descriptionFactory),
new ReturnFactory($typeResolver, $descriptionFactory),
new PropertyFactory($typeResolver, $descriptionFactory),
new PropertyReadFactory($typeResolver, $descriptionFactory),
new PropertyWriteFactory($typeResolver, $descriptionFactory),
new MethodFactory($typeResolver, $descriptionFactory)
);
$tagFactory->addService($descriptionFactory);
$tagFactory->addService(new TypeResolver($fqsenResolver));
$tagFactory->addService($typeResolver);
$tagFactory->registerTagHandler('param', $phpstanTagFactory);
$tagFactory->registerTagHandler('var', $phpstanTagFactory);
$tagFactory->registerTagHandler('return', $phpstanTagFactory);
$tagFactory->registerTagHandler('property', $phpstanTagFactory);
$tagFactory->registerTagHandler('property-read', $phpstanTagFactory);
$tagFactory->registerTagHandler('property-write', $phpstanTagFactory);
$tagFactory->registerTagHandler('method', $phpstanTagFactory);
$docBlockFactory = new self($descriptionFactory, $tagFactory);
foreach ($additionalTags as $tagName => $tagHandler) {
@ -111,9 +136,9 @@ final class DocBlockFactory implements DocBlockFactoryInterface
}
/**
* @param class-string<Tag> $handler
* @param class-string<Tag>|Factory $handler
*/
public function registerTagHandler(string $tagName, string $handler): void
public function registerTagHandler(string $tagName, $handler): void
{
$this->tagFactory->registerTagHandler($tagName, $handler);
}
@ -138,6 +163,7 @@ final class DocBlockFactory implements DocBlockFactoryInterface
}
// phpcs:disable
/**
* Splits the DocBlock into a template marker, summary, description and block of tags.
*
@ -149,7 +175,7 @@ final class DocBlockFactory implements DocBlockFactoryInterface
*
* @author Richard van Velzen (@_richardJ) Special thanks to Richard for the regex responsible for the split.
*/
private function splitDocBlock(string $comment) : array
private function splitDocBlock(string $comment): array
{
// phpcs:enable
// Performance improvement cheat: if the first character is an @ then only tags are in this DocBlock. This
@ -227,7 +253,7 @@ final class DocBlockFactory implements DocBlockFactoryInterface
/**
* Creates the tag objects.
*
* @param string $tags Tag block to parse.
* @param string $tags Tag block to parse.
* @param Types\Context $context Context of the parsed Tag
*
* @return DocBlock\Tag[]
@ -240,7 +266,7 @@ final class DocBlockFactory implements DocBlockFactoryInterface
}
$result = [];
$lines = $this->splitTagBlockIntoTagLines($tags);
$lines = $this->splitTagBlockIntoTagLines($tags);
foreach ($lines as $key => $tagLine) {
$result[$key] = $this->tagFactory->create(trim($tagLine), $context);
}

View File

@ -14,7 +14,7 @@ interface DocBlockFactoryInterface
*
* @param array<string, class-string<Tag>> $additionalTags
*/
public static function createInstance(array $additionalTags = []): DocBlockFactory;
public static function createInstance(array $additionalTags = []): self;
/**
* @param string|object $docblock