phpdocumentor/reflection-docblock
PHPDoc-compliant DocBlock parser from phpDocumentor. Parse summaries, descriptions and tags from doc comments or reflection objects using DocBlockFactory, enabling annotation-like metadata and easy access to structured DocBlock information.
Installation:
composer require phpdocumentor/reflection-docblock
Add to composer.json if using Laravel's autoloader:
"autoload": {
"psr-4": {
"App\\": "app/",
"Database\\": "database/",
"phpDocumentor\\Reflection\\": "vendor/phpdocumentor/reflection-docblock/src/"
}
}
Run composer dump-autoload.
First Use Case: Parse a docblock from a class method:
use phpDocumentor\Reflection\DocBlockFactory;
use ReflectionClass;
$reflectionClass = new ReflectionClass(\App\Models\User::class);
$method = $reflectionClass->getMethod('find');
$docblock = DocBlockFactory::createInstance()->create($method->getDocComment());
// Access summary/description/tags
$summary = $docblock->getSummary();
$tags = $docblock->getTagsByName('param');
Core Classes:
DocBlockFactory: Entry point for creating DocBlock objects.DocBlock: Parsed docblock with methods like getSummary(), getDescription(), getTags().Tag: Represents individual docblock tags (e.g., @param, @return).StandardTagFactory: Default factory for common tags (extend for custom tags).Laravel Integration:
ReflectionClass or ReflectionMethod to parse docblocks from models/controllers.@param types).Examples:
Browse /docs/examples in the package repo for real-world usage patterns.
$reflection = new ReflectionMethod(\App\Http\Controllers\UserController::class, 'store');
$docblock = DocBlockFactory::createInstance()->create($reflection->getDocComment());
// Extract @param types for request validation
$params = $docblock->getTagsByName('param');
foreach ($params as $param) {
$type = $param->getType();
// Use $type to validate incoming request data
}
Extend StandardTagFactory to support custom tags (e.g., @api):
use phpDocumentor\Reflection\Types\Context;
use phpDocumentor\Reflection\DocBlock\Tags\InlineTag;
class ApiTagFactory extends StandardTagFactory
{
public function create(string $content, Context $context): InlineTag
{
return new InlineTag('api', $content, $context);
}
}
// Register in DocBlockFactory
$factory = DocBlockFactory::createInstance();
$factory->setTagFactory(new ApiTagFactory());
Convert a DocBlock back to a string (e.g., for API docs):
$docblock = DocBlockFactory::createInstance()->create($rawDocblock);
$rendered = $docblock->render();
Use middleware to validate route parameters against controller method docblocks:
public function handle(Request $request, Closure $next)
{
$controller = $request->route()->getController();
$method = new ReflectionMethod($controller[0], $controller[1]);
$docblock = DocBlockFactory::createInstance()->create($method->getDocComment());
$params = $docblock->getTagsByName('param');
foreach ($params as $param) {
$type = $param->getType();
if (!$type->acceptsValue($request->input($param->getVariableName()))) {
throw new \InvalidArgumentException("Invalid type for {$param->getVariableName()}");
}
}
return $next($request);
}
Caching Parsed DocBlocks:
Cache DocBlock objects in Laravel's cache system to avoid reparsing:
$cacheKey = 'docblock:'.md5($reflection->getName());
$docblock = Cache::remember($cacheKey, now()->addHours(1), function () use ($reflection) {
return DocBlockFactory::createInstance()->create($reflection->getDocComment());
});
Type Resolution:
Use phpdocumentor/type-resolver (dependency) to resolve complex types:
$type = $param->getType();
$resolver = new \phpDocumentor\Reflection\TypeResolver();
$resolvedType = $resolver->resolve($type, new \phpDocumentor\Reflection\Fqsen\Fqsen('App\Models'));
Testing:
Mock DocBlock objects in unit tests:
$mockDocblock = $this->createMock(\phpDocumentor\Reflection\DocBlock::class);
$mockDocblock->method('getTagsByName')->willReturn([new \phpDocumentor\Reflection\DocBlock\Tags\ParamTag('param', 'string $id', $context)]);
Laravel Service Provider:
Bind the factory as a singleton in AppServiceProvider:
public function register()
{
$this->app->singleton(DocBlockFactory::class, function () {
return DocBlockFactory::createInstance();
});
}
Deprecated Features in v6:
@param tags without variable names (e.g., @param string Description). This is deprecated and will be removed in future versions.StandardTagFactory for custom tags.Type Resolution Limitations:
Array<string>) may not be fully supported. Use phpdocumentor/type-resolver for complex types.null before resolving:
$type = $param->getType();
if ($type === null) {
throw new \RuntimeException("Missing type for @param tag");
}
Multiline Descriptions:
PHP 8+ Deprecations:
?string) may trigger warnings. Use null checks or update to the latest package version.Escaped DocBlocks:
$docblock = <<<'DOC'
/**
* Summary
*/
DOC;
Inspect Raw DocBlocks:
Use var_dump() to debug raw docblock strings before parsing:
var_dump($reflection->getDocComment());
Tag-Specific Issues:
@param without variable), use try-catch:
try {
$docblock = DocBlockFactory::createInstance()->create($rawDocblock);
} catch (\phpDocumentor\Reflection\Exception\InvalidTagException $e) {
Log::error("Invalid docblock tag: {$e->getMessage()}");
}
Type Resolution Errors:
try {
$resolvedType = $resolver->resolve($type, $context);
} catch (\phpDocumentor\Reflection\TypeResolver\Exception\UnknownType $e) {
$resolvedType = new \phpDocumentor\Reflection\Types\Object_('mixed');
}
Performance:
@template tags) can be slow. Cache results or use lazy loading.Custom Tag Parsers:
Extend StandardTagFactory to handle non-standard tags (e.g., @deprecated with custom logic):
class DeprecatedTagFactory extends StandardTagFactory
{
public function create(string $content, Context $context): InlineTag
{
$tag = new InlineTag('deprecated', $content, $context);
$tag->setDeprecationReason($this->extractReason($content));
return $tag;
}
private function extractReason(string $content): string
{
// Custom logic to parse deprecation reason
}
}
DocBlock Preprocessing:
Use Laravel's booted event to preprocess docblocks (e.g., normalize types):
public function booted
How can I help you explore Laravel packages today?