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

Analyzer Laravel Package

graham-campbell/analyzer

Analyzer by Graham Campbell statically checks your PHP code to ensure referenced classes actually exist, helping catch typos and missing dependencies early. Supports PHP 8.1–8.5 and integrates with PHPUnit 10–13.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install via Composer (dev dependency):
    composer require --dev graham-campbell/analyzer:^5.1
    
  2. Add to PHPUnit (create/update phpunit.xml):
    <phpunit>
        <extensions>
            <extension class="GrahamCampbell\Analyzer\PHPUnit\AnalyzerExtension"/>
        </extensions>
    </phpunit>
    
  3. Run tests:
    ./vendor/bin/phpunit
    

First Use Case: Basic Class Validation

Create a test class extending GrahamCampbell\Analyzer\TestCase:

use GrahamCampbell\Analyzer\TestCase;

class ClassReferenceTest extends TestCase
{
    protected function getPaths(): array
    {
        return [__DIR__.'/../src'];
    }

    public function testClassReferences()
    {
        $this->assertValidClasses();
    }
}

Run the test to validate all class references in src/.


Implementation Patterns

1. Integration with Laravel Projects

  • Service Providers: Validate register()/boot() methods for missing classes (e.g., App\Services\PaymentService).
  • Facades: Check Facade::class references in registerFacade().
  • API Resources: Ensure @property PHPDoc matches actual class properties.

Example: Validating a Service Provider

use GrahamCampbell\Analyzer\TestCase;

class PaymentServiceProviderTest extends TestCase
{
    protected function getPaths(): array
    {
        return [app_path('Providers/PaymentServiceProvider.php')];
    }

    public function testServiceProviderReferences()
    {
        $this->assertValidClasses();
    }
}

2. Custom Ignore Rules

Override getIgnored() to exclude specific classes (e.g., third-party or dynamic classes):

protected function getIgnored(): array
{
    return [
        'App\Services\DynamicClassLoader', // Dynamically loaded
        'Vendor\Package\AbstractBase',     // External, no control
    ];
}

3. File Filtering

Use shouldAnalyzeFile() to skip specific files (e.g., migrations, config):

protected function shouldAnalyzeFile(string $file): bool
{
    return !Str::contains($file, ['migrations/', 'config/']);
}

4. PHPDoc Validation

Analyzer checks @property, @method, and @var annotations. Example:

/**
 * @property-read App\Models\User $user
 */
class UserResource extends JsonResource
{
    // ...
}

If App\Models\User doesn’t exist, the test fails.

5. CI/CD Workflow

Add to .github/workflows/ci.yml:

- name: Run Analyzer
  run: ./vendor/bin/phpunit --extension GrahamCampbell\Analyzer\PHPUnit\AnalyzerExtension

6. Local Development

Run locally with:

./vendor/bin/phpunit --filter=ClassReferenceTest

Gotchas and Tips

Pitfalls

  1. False Positives with Namespaces:

    • If use App; is used (without full namespace), Analyzer will fail. Solution: Use full paths (e.g., use App\Models\User).
    • Workaround: Add the base namespace to getIgnored() if unavoidable.
  2. Dynamic Class Loading:

    • Classes loaded via eval(), class_alias(), or runtime namespace resolution (e.g., App\) will trigger failures. Solution: Exclude them in getIgnored().
  3. PHPDoc Parsing Quirks:

    • Complex PHPDoc (e.g., @mixin, custom tags) may cause parsing errors. Solution: Simplify PHPDoc or report issues to the package maintainer.
  4. Performance with Large Codebases:

    • Analyzing 10K+ files may slow down CI. Solution:
      • Limit paths in getPaths().
      • Run in parallel (PHPUnit’s --parallel flag).
  5. PHPUnit Version Mismatch:

    • Ensure PHPUnit version matches the package’s supported range (v5.1 requires PHPUnit 10–13). Solution: Update phpunit.xml or downgrade Analyzer.

Debugging Tips

  • Verbose Output: Enable debug mode in phpunit.xml:
    <phpunit>
        <extensions>
            <extension class="GrahamCampbell\Analyzer\PHPUnit\AnalyzerExtension">
                <arguments>
                    <argument name="debug" value="true"/>
                </arguments>
            </extension>
        </extensions>
    </phpunit>
    
  • Check Raw Errors: Use getErrors() in tests:
    public function testClassReferences()
    {
        $errors = $this->getErrors();
        $this->assertEmpty($errors, implode("\n", $errors));
    }
    

Extension Points

  1. Custom Analyzers: Extend GrahamCampbell\Analyzer\Analyzer to add logic (e.g., validate interfaces):

    class CustomAnalyzer extends Analyzer
    {
        protected function analyzeNode(Node $node): void
        {
            if ($node instanceof Class_) {
                $this->validateInterface($node);
            }
        }
    }
    
  2. Hook into PHPUnit Events: Listen for TestListener events to integrate with other tools:

    use GrahamCampbell\Analyzer\Events\AnalysisFailed;
    
    AnalysisFailed::listen(function (AnalysisFailed $event) {
        // Log to Slack/Teams
    });
    
  3. Override Node Processing: Customize provideFilesToCheck() to analyze non-PHP files (e.g., Blade templates with @class directives):

    protected function provideFilesToCheck(): array
    {
        return array_merge(
            $this->getPaths(),
            [resource_path('views/*.blade.php')]
        );
    }
    

Config Quirks

  • Case Sensitivity: Analyzer respects filesystem case sensitivity. On case-insensitive filesystems (e.g., Windows), ensure use statements match the actual file case.
  • Autoloading: The package uses Composer autoloading. If classes are loaded via custom PSR-4 rules, ensure they’re registered in composer.json.
  • Traits and Interfaces: These are validated like classes, but abstract methods in interfaces won’t trigger errors unless referenced.

Pro Tips

  • Pair with PHPStan: Use Analyzer in CI for fast class validation, then run PHPStan for deeper analysis.
  • Git Hooks: Add a pre-commit hook to run Analyzer locally:
    composer require --dev laravel-zero/framework
    echo 'php artisan analyzer' >> .git/hooks/pre-commit
    
  • Laravel Forge/Envoyer: Deploy only if tests pass:
    ./vendor/bin/phpunit --extension GrahamCampbell\Analyzer\PHPUnit\AnalyzerExtension || exit 1
    
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