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 Laravel Package

phpdocumentor/reflection

Static PHP code reflection library that parses files without executing them. Builds an object graph of your project’s structure, including DocBlocks. Can analyze code from PHP 5.2 up to your installed version; suitable for reflecting whole files or projects.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require phpdocumentor/reflection:~6.0
    

    Ensure vendor/autoload.php is included in your project.

  2. Basic Reflection:

    use phpDocumentor\Reflection\Php\ProjectFactory;
    use phpDocumentor\Reflection\File\LocalFile;
    
    // Initialize factory with defaults (PHP 7 parser preferred)
    $factory = ProjectFactory::createInstance();
    
    // Reflect a single file
    $project = $factory->create(
        'MyProject',
        [new LocalFile(__DIR__ . '/path/to/YourClass.php')]
    );
    
    // Access the project's root namespace
    $rootNamespace = $project->getRootNamespace();
    
  3. First Use Case: Inspect a class's methods and properties:

    $class = $rootNamespace->getClass('YourClass');
    foreach ($class->getMethods() as $method) {
        echo $method->getName() . "\n";
        echo $method->getDocBlock()->getSummary() . "\n";
    }
    

Implementation Patterns

Core Workflows

1. Project-Wide Analysis

// Reflect an entire directory (e.g., Laravel's `app/` folder)
$files = [];
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(__DIR__ . '/app')) as $file) {
    if ($file->isFile() && $file->getExtension() === 'php') {
        $files[] = new LocalFile($file->getPathname());
    }
}
$project = $factory->create('LaravelApp', $files);

2. Type Resolution in Expressions

Extract types from method argument defaults:

$method = $class->getMethod('example');
$param = $method->getParameters()[0];
$defaultValue = $param->getDefaultValue();
$type = $defaultValue->getType(); // e.g., `String_`, `Int_`, `Array_`

3. DocBlock Parsing

$docBlock = $method->getDocBlock();
$summary = $docBlock->getSummary(); // First line after `@`
$tags = $docBlock->getTags(); // `@param`, `@return`, etc.

4. Attribute Reflection

$attributes = $class->getAttributes();
foreach ($attributes as $attr) {
    echo $attr->getName() . "\n";
    foreach ($attr->getArguments() as $arg) {
        echo "  - " . $arg->getName() . ": " . $arg->getValue() . "\n";
    }
}

Integration Tips

Laravel-Specific Use Cases

  1. Service Provider Discovery: Use reflection to dynamically load providers without config/app.php:

    $providers = [];
    foreach ($project->getNamespaces() as $namespace) {
        if ($namespace->getName() === 'App\\Providers') {
            foreach ($namespace->getClasses() as $class) {
                if (is_subclass_of($class->getFqsen(), \Illuminate\Support\ServiceProvider::class)) {
                    $providers[] = $class->getFqsen();
                }
            }
            break;
        }
    }
    
  2. Route Model Binding: Reflect route parameters to resolve models:

    $controller = $project->getClass('App\\Http\\Controllers\\UserController');
    $method = $controller->getMethod('show');
    $param = $method->getParameters()[1]; // Assume second param is the model
    $modelClass = $param->getType()->getFqsen(); // e.g., `App\Models\User`
    
  3. Middleware Pipelines: Dynamically build middleware stacks from annotated routes:

    $route = $project->getClass('Route'); // Hypothetical route class
    $method = $route->getMethod('get');
    $attributes = $method->getAttributes('middleware');
    $middleware = collect($attributes)->pluck('arguments')->flatten()->toArray();
    

Performance Optimization

  • Cache Projects: Serialize the Project object to avoid re-parsing:

    $cachePath = storage_path('framework/reflection.cache');
    if (!file_exists($cachePath)) {
        $project = $factory->create('App', $files);
        file_put_contents($cachePath, serialize($project));
    } else {
        $project = unserialize(file_get_contents($cachePath));
    }
    
  • Lazy Loading: Use iterators to avoid loading entire projects into memory:

    foreach ($project->getNamespaces() as $namespace) {
        foreach ($namespace->getClasses() as $class) {
            // Process class without loading all at once
        }
    }
    

Gotchas and Tips

Pitfalls

  1. Parser Version Mismatch:

    • The library defaults to PHP 7 parser but may fail on older PHP versions (e.g., 5.2–5.6).
    • Fix: Ensure your project’s composer.json and PHP version align. Use phpDocumentor/reflection:^5.3 for legacy support.
  2. Circular References:

    • Self-referencing constants or traits may cause infinite loops.
    • Fix: Upgrade to ^6.4.4+ (fixed in #697).
  3. Attribute Limitations:

    • Runtime attribute classes (e.g., #[Some\Attribute]) are not resolved; only their definition is parsed.
    • Workaround: Use getAttributes() to inspect metadata, then manually resolve types if needed.
  4. DocBlock Inconsistencies:

    • Malformed DocBlocks (e.g., unclosed tags) may throw parsing errors.
    • Tip: Validate with phpstan/extension-installer or phpdocumentor/phpdocumentor.
  5. PHP 8+ Features:

    • Some features (e.g., read-only properties, enums) require ^6.0+.
    • Example: Virtual properties (PHP 8.2+) are supported via getVirtualProperties().

Debugging

  1. Parse Errors:

    • Enable verbose output to pinpoint issues:
      $factory->getParser()->setAttribute(ParserConstants::ATTR_ERROR_HANDLER, function ($error) {
          error_log("Parse Error: {$error->getMessage()} in {$error->getFile()} at line {$error->getLine()}");
      });
      
  2. Type Resolution Issues:

    • Default values like null or true may resolve to Null_ or True_ types (fixed in ^6.4.2).
    • Debug: Use var_dump($defaultValue->getType()->getFqsen()) to inspect resolved types.
  3. Memory Usage:

    • Large projects (e.g., Laravel) may consume significant memory.
    • Mitigation: Process files in batches or use Project::getFiles() to iterate.

Extension Points

  1. Custom Factories: Extend phpDocumentor\Reflection\Php\Factory to handle domain-specific elements:

    class CustomFactory extends \phpDocumentor\Reflection\Php\Factory {
        protected function createCustomElement(Node $node) {
            return new CustomElement($node);
        }
    }
    
  2. Reducers: Modify parsed elements post-creation (e.g., for attributes):

    $factory->addReducer(new class implements Reducer {
        public function reduce(Node $node, Node $parent) {
            if ($node instanceof Attribute) {
                $node->setProcessed(true); // Custom logic
            }
            return $node;
        }
    });
    
  3. Strategies: Override parsing behavior (e.g., ignore certain files):

    $factory->addStrategy(new class implements Strategy {
        public function shouldProcess(File $file) {
            return !str_contains($file->getPath(), 'vendor');
        }
    });
    

Laravel-Specific Quirks

  1. Facade Resolution: Facades (e.g., Route::get()) are not directly reflectable. Instead, reflect the underlying class:

    $routeClass = $project->getClass('Illuminate\Routing\Router');
    
  2. Dynamic Properties: Laravel uses dynamic properties (e.g., $request->input). These are not statically analyzable but can be inferred via:

    $method = $controller->getMethod('store');
    $docBlock = $method->getDocBlock();
    if ($docBlock->hasTag('property-read')) {
        // Infer dynamic property usage
    }
    
  3. Service Container: Resolve bound classes via reflection:

    $container = app();
    $binding = $project->getClass('App\\Providers\\AppServiceProvider');
    $method = $binding->get
    
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.
hamzi/corewatch
minionfactory/raw-hydrator
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