Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Reflection Docblock Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. 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.

  2. 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');
    

Where to Look First

  • 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:

    • Use with Laravel's ReflectionClass or ReflectionMethod to parse docblocks from models/controllers.
    • Example: Validate API requests against method docblocks (e.g., @param types).
  • Examples: Browse /docs/examples in the package repo for real-world usage patterns.


Implementation Patterns

Workflows

1. Parsing DocBlocks from Reflection Objects

$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
}

2. Custom Tag Handling

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());

3. Dynamic DocBlock Generation

Convert a DocBlock back to a string (e.g., for API docs):

$docblock = DocBlockFactory::createInstance()->create($rawDocblock);
$rendered = $docblock->render();

4. Laravel-Specific: Route/Controller DocBlock Validation

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);
}

Integration Tips

  1. 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());
    });
    
  2. 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'));
    
  3. 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)]);
    
  4. Laravel Service Provider: Bind the factory as a singleton in AppServiceProvider:

    public function register()
    {
        $this->app->singleton(DocBlockFactory::class, function () {
            return DocBlockFactory::createInstance();
        });
    }
    

Gotchas and Tips

Pitfalls

  1. Deprecated Features in v6:

    • Avoid using @param tags without variable names (e.g., @param string Description). This is deprecated and will be removed in future versions.
    • Static factory interfaces are deprecated; use StandardTagFactory for custom tags.
  2. Type Resolution Limitations:

    • Generics (e.g., Array<string>) may not be fully supported. Use phpdocumentor/type-resolver for complex types.
    • Always check if a tag's type is null before resolving:
      $type = $param->getType();
      if ($type === null) {
          throw new \RuntimeException("Missing type for @param tag");
      }
      
  3. Multiline Descriptions:

    • Indented lines in descriptions may cause parsing issues. Use consistent indentation (e.g., 4 spaces) or avoid indentation in docblocks.
  4. PHP 8+ Deprecations:

    • Explicit nullable deprecations (e.g., ?string) may trigger warnings. Use null checks or update to the latest package version.
  5. Escaped DocBlocks:

    • Nested docblocks (e.g., in heredoc strings) may not parse correctly. Use raw strings or escape properly:
      $docblock = <<<'DOC'
      /**
       * Summary
       */
      DOC;
      

Debugging Tips

  1. Inspect Raw DocBlocks: Use var_dump() to debug raw docblock strings before parsing:

    var_dump($reflection->getDocComment());
    
  2. Tag-Specific Issues:

    • For malformed tags (e.g., @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()}");
      }
      
  3. Type Resolution Errors:

    • Wrap type resolution in a try-catch:
      try {
          $resolvedType = $resolver->resolve($type, $context);
      } catch (\phpDocumentor\Reflection\TypeResolver\Exception\UnknownType $e) {
          $resolvedType = new \phpDocumentor\Reflection\Types\Object_('mixed');
      }
      
  4. Performance:

    • Parsing large docblocks (e.g., with many @template tags) can be slow. Cache results or use lazy loading.

Extension Points

  1. 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
        }
    }
    
  2. DocBlock Preprocessing: Use Laravel's booted event to preprocess docblocks (e.g., normalize types):

    public function booted
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope
anil/file-picker
broqit/fields-ai