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

Better Reflection Laravel Package

roave/better-reflection

Enhanced PHP reflection for static analysis: reflect classes without loading them, from PHP code strings or closures, extract AST from functions/methods, and read type declarations and docblocks. Feature-rich but slower than native reflection.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation: Add via Composer:
    composer require roave/better-reflection
    
  2. Basic Reflection: Initialize with Composer autoloader (default):
    use Roave\BetterReflection\BetterReflection;
    
    $reflector = (new BetterReflection())->reflector();
    $class = $reflector->reflectClass(\App\Models\User::class);
    
  3. First Use Case: Inspect a class's methods, properties, or AST:
    $methods = $class->getMethods();
    $ast = $class->getMethod('someMethod')->getDocComment();
    

Key Entry Points

  • BetterReflection: Main facade for creating reflectors.
  • reflector(): Returns a DefaultReflector (uses Composer autoloader by default).
  • findReflectionsOnLine(): Helper for line-based reflection (e.g., IDE tooling).

Implementation Patterns

1. Reflecting Unloaded Classes

Use SingleFileSourceLocator for classes not autoloaded by Composer:

use Roave\BetterReflection\SourceLocator\SingleFileSourceLocator;

$locator = new SingleFileSourceLocator('/path/to/UnloadedClass.php');
$reflector = new \Roave\BetterReflection\Reflector\DefaultReflector($locator);
$class = $reflector->reflectClass('UnloadedClass');

2. Reflecting from PHP Strings

Use StringSourceLocator for dynamic code analysis:

use Roave\BetterReflection\SourceLocator\StringSourceLocator;

$locator = new StringSourceLocator('class DynamicClass { public function foo() {} }');
$reflector = new \Roave\BetterReflection\Reflector\DefaultReflector($locator);
$class = $reflector->reflectClass('DynamicClass');

3. Line-Based Reflection (IDE Tooling)

Find reflections on specific lines (e.g., for error reporting):

$finder = (new BetterReflection())->findReflectionsOnLine();
$reflection = $finder(__FILE__, __LINE__ - 1); // Reflect previous line

4. AST Extraction

Get Abstract Syntax Tree for static analysis:

$method = $class->getMethod('someMethod');
$ast = $method->getNode(); // Returns PhpParser\Node\Stmt\ClassMethod

5. Type Introspection

Extract parameter/return types (PHP 7+):

$method = $class->getMethod('typedMethod');
$returnType = $method->getReturnType(); // Returns ReflectionType
$params = $method->getParameters();
foreach ($params as $param) {
    $type = $param->getType(); // ReflectionType or null
}

6. Integration with Laravel

  • Service Provider: Bind BetterReflection in AppServiceProvider:
    public function register()
    {
        $this->app->singleton(BetterReflection::class, function () {
            return new BetterReflection();
        });
    }
    
  • Artisan Commands: Use for code analysis tools:
    use Roave\BetterReflection\BetterReflection;
    
    class AnalyzeCommand extends Command
    {
        protected $reflector;
    
        public function __construct()
        {
            $this->reflector = (new BetterReflection())->reflector();
        }
    
        public function handle()
        {
            $class = $this->reflector->reflectClass(\App\Models\User::class);
            // Analyze logic...
        }
    }
    

7. Caching Reflections

Avoid repeated parsing by caching reflectors:

$cache = new \Roave\BetterReflection\SourceLocator\CachedLocator(
    new ComposerSourceLocator(),
    new \Symfony\Component\Cache\Adapter\FilesystemAdapter()
);
$reflector = new \Roave\BetterReflection\Reflector\DefaultReflector($cache);

Gotchas and Tips

Pitfalls

  1. Runtime Performance:

    • Issue: BetterReflection is not optimized for runtime use (e.g., instantiating classes).
    • Fix: Use native \ReflectionClass for runtime operations. BetterReflection is for static analysis only.
  2. Closure Limitations:

    • Issue: Cannot reflect closures directly (e.g., ReflectionMethod::createFromClosure unsupported).
    • Fix: Use StringSourceLocator to parse closure strings or rely on ReflectionFunction.
  3. Autoloader Dependencies:

    • Issue: AutoloadSourceLocator fails if Composer autoloader doesn’t resolve classes to files.
    • Fix: Use SingleFileSourceLocator or StringSourceLocator for custom paths.
  4. AST vs. Reflection:

    • Issue: getNode() returns a PhpParser\Node (not a Reflection* object).
    • Fix: Use getDocComment(), getReturnType(), etc., for reflection data; use getNode() for AST traversal.
  5. Unsupported Methods:

    • Issue: Methods like newInstance(), getExtension(), or getClosureThis() throw exceptions.
    • Fix: Check compatibility docs before use.
  6. PHP 8 Attributes:

    • Issue: Attribute reflection (ReflectionAttribute) has limited support (e.g., newInstance() unsupported).
    • Fix: Use getArguments() and getName() for static analysis.

Debugging Tips

  1. Verify Source Locators:

    • Check if your SourceLocator correctly resolves files:
      $locator = new ComposerSourceLocator();
      $source = $locator->findFileForClass(\App\Models\User::class);
      if (!$source) {
          throw new \RuntimeException("Class not found in autoloader");
      }
      
  2. Handle Missing Classes Gracefully:

    • Wrap reflector calls in try-catch:
      try {
          $class = $reflector->reflectClass('NonExistentClass');
      } catch (\Roave\BetterReflection\Exception\IdentifierNotFoundException $e) {
          // Fallback logic
      }
      
  3. AST Debugging:

    • Dump nodes for complex methods:
      $node = $method->getNode();
      var_dump($node->getStmts()); // Inspect statements
      
  4. Line-Based Reflection:

    • Use findReflectionsOnLine() carefully—it may return null for non-declaration lines:
      $reflection = $finder->find(__FILE__, 42);
      if (!$reflection) {
          $this->error("No reflection found on line 42");
      }
      

Extension Points

  1. Custom Source Locators:

    • Implement SourceLocatorInterface for custom paths (e.g., vendor-specific files):
      class CustomSourceLocator implements SourceLocatorInterface
      {
          public function findFileForClass($class): ?string
          {
              return '/custom/path/' . str_replace('\\', '/', $class) . '.php';
          }
      }
      
  2. AST Transformations:

    • Use PhpParser to modify AST nodes before reflection:
      use PhpParser\ParserFactory;
      
      $parser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
      $stmts = $parser->parse($sourceCode);
      // Transform $stmts...
      $reflector->reflectClassFromAst($stmts);
      
  3. Caching Strategies:

    • Extend CachedLocator to add custom cache keys or invalidation logic:
      $cache = new CachedLocator(
          new ComposerSourceLocator(),
          new \Symfony\Component\Cache\Adapter\TagAwareAdapter()
      );
      $cache->invalidateTag('model'); // Invalidate all model-related reflections
      
  4. Integration with PHPStan/Psalm:

    • Use BetterReflection as a backend for static analyzers by implementing their ReflectionProvider interfaces.

Config Quirks

  1. Composer Autoloader:

    • Ensure autoload and autoload-dev are configured in composer.json for full coverage.
  2. PHP Version:

    • Some features (e.g., ReflectionType for PHP 7.4+) require PHP 7.4+. Test on target versions.
  3. Memory Usage:

    • Parsing large codebases (e.g., entire Laravel) may spike memory. Use CachedLocator to mitigate.
  4. Case Sensitivity:

    • Class names in reflectClass() are case-sensitive. Use strtolower() if needed for case-insensitive environments.

Pro Tips

  • Combine with phpDocumentor: Use getDocComment() to
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