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

Dead Code Detector Laravel Package

shipmonk/dead-code-detector

PHPStan extension that finds unused PHP code: dead methods, properties, constants, enum cases, cycles, and transitive “dead-tested” members. Supports popular frameworks like Symfony and can auto-remove dead code. Configurable detection and usage providers.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require --dev shipmonk/dead-code-detector
    

    Add the extension to your phpstan.neon:

    includes:
        - vendor/shipmonk/dead-code-detector/rules.neon
    
  2. First Run:

    vendor/bin/phpstan analyse --level=max
    

    Ensure you analyze the entire codebase (both src and tests) to detect all usages.

  3. First Use Case: Run the detector on a Laravel project to identify unused methods, constants, or properties in your App namespace. Example output:

    Unused App\Services\UserService::legacyMethod
    

Implementation Patterns

Daily Workflow

  1. Pre-Commit Hook: Integrate with Git hooks to run phpstan with --error-format=removeDeadCode before commits:

    vendor/bin/phpstan analyse --error-format=removeDeadCode --level=max
    

    Automatically removes dead code if no false positives are detected.

  2. CI Pipeline: Add a step to run the detector in CI (e.g., GitHub Actions):

    - name: Detect dead code
      run: vendor/bin/phpstan analyse --level=max
    

    Fail the build if dead code is found (adjust --error-format as needed).

  3. Laravel-Specific Patterns:

    • Routes: Detect unused route callbacks (e.g., Route::get('/old', [UserController::class, 'unusedMethod'])).
    • Events: Identify unused event listeners or subscribers.
    • Eloquent: Flag unused model methods, observers, or query scopes.
    • Twig: Detect unused Twig filters/functions or view objects passed to templates.
  4. Test-Driven Development: Use the tests usage excluder to separate test-only usages from production code:

    parameters:
        shipmonkDeadCode:
            usageExcluders:
                tests:
                    enabled: true
                    devPaths:
                        - %currentWorkingDirectory%/tests
    

    This ensures dead code in src used only in tests is reported but not auto-removed.

  5. Custom Providers: Extend ReflectionBasedMemberUsageProvider for framework-specific logic (e.g., Laravel’s #[AsTwigComponent] or #[LiveAction]):

    class LaravelLiveComponentProvider extends ReflectionBasedMemberUsageProvider {
        public function shouldMarkMethodAsUsed(ReflectionMethod $method): ?VirtualUsageData {
            if ($method->hasAttribute(LiveAction::class)) {
                return VirtualUsageData::withNote('Used in LiveComponent');
            }
            return null;
        }
    }
    

    Register in phpstan.neon:

    services:
        - class: App\LaravelLiveComponentProvider
          tags: [shipmonk.deadCode.memberUsageProvider]
    

Gotchas and Tips

Pitfalls

  1. False Positives in Dynamic Code:

    • The detector may flag methods as dead if they are called dynamically (e.g., via call_user_func() or reflection). Use custom MemberUsageProvider to handle these cases.
    • Example: Override shouldMarkMethodAsUsed to return VirtualUsageData for dynamically invoked methods.
  2. Transitive Dead Code:

    • By default, only the root dead method is reported. Enable detailed reporting for transitive dead methods:
      parameters:
          shipmonkDeadCode:
              reportTransitivelyDeadMethodAsSeparateError: true
      
    • This may flood output; use sparingly.
  3. Test Excluder Misconfiguration:

    • If tests excluder is enabled but paths are misconfigured, dead code used in tests might be incorrectly reported as "unused in production." Verify devPaths in composer.json or explicitly define them.
  4. Auto-Removal Risks:

    • Running --error-format=removeDeadCode will permanently delete dead code. Review changes carefully, especially in shared repositories.
    • Test auto-removal locally first:
      vendor/bin/phpstan analyse --error-format=removeDeadCode --generate-report=report.txt
      
  5. Framework-Specific Quirks:

    • Laravel: Ensure phpstan/phpstan-symfony is installed for DIC support. Configure containerXmlPath if using custom container paths.
    • Doctrine: Attributes like #[PreFlush] may not be detected if the event system isn’t fully analyzed. Run PHPStan with --level=max to include all rules.
    • Twig: View objects passed to templates must be explicitly typed or referenced in phpstan.neon for detection.

Debugging Tips

  1. Inspect Usages: Use --generate-report=report.txt to see detailed usage origins. Example:

    📍 Usage origin: src/Http/Controllers/UserController.php:42 (Route::get('/users', [UserController::class, 'index']))
    
  2. Disable Specific Checks: Temporarily disable checks for troubleshooting:

    parameters:
        shipmonkDeadCode:
            detect:
                deadMethods: false
                deadProperties: { neverRead: false }
    
  3. Custom Excluders: Implement MemberUsageExcluder to ignore specific usages (e.g., legacy code or third-party calls):

    class LegacyCodeExcluder implements MemberUsageExcluder {
        public function shouldExclude(ClassMemberUsage $usage, Node $node, Scope $scope): bool {
            return str_contains($usage->getClassRef()->getClassName(), 'Legacy');
        }
    }
    
  4. IDE Integration: Configure editorUrl in phpstan.neon to open files directly in your IDE:

    parameters:
        editorUrl: 'phpstorm://open?file=%f&line=%l'
    

Extension Points

  1. Custom Usage Providers:

    • For unsupported frameworks (e.g., custom event systems), implement MemberUsageProvider to parse AST nodes and emit usages.
    • Example: Detect calls to a custom event dispatcher:
      public function getUsages(Node $node, Scope $scope): array {
          if ($node instanceof MethodCall && $scope->getType($node->var)->isInstanceOf(EventDispatcher::class)) {
              return [new ClassMethodUsage($usageOrigin, new ClassMethodRef($node->name->toString()))];
          }
          return [];
      }
      
  2. Post-Processing: Use PHPStan’s ErrorFormatter to customize output or integrate with tools like PHP-CS-Fixer:

    use ShipMonk\PHPStan\DeadCode\ErrorFormatter\RemoveDeadCodeErrorFormatter;
    $errorFormatter = new RemoveDeadCodeErrorFormatter();
    $errorFormatter->processFile($file, $errors);
    
  3. Performance:

    • Exclude large directories (e.g., vendor/) from analysis to speed up runs:
      excludeFiles:
          - vendor/**
          - node_modules/**
      
    • Cache results with --memory-limit=2G for large codebases.
  4. Laravel-Specific:

    • Service Providers: Use #[AutowireCallable] or #[AutowireLocator] attributes to detect dead methods in service containers.
    • Middleware: Detect unused middleware by analyzing app/Http/Kernel.php and Route::middleware() calls.
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.
codraw/entity-migrator
codraw/doctrine-extra
codraw/aws-tool-kit
codraw/validator
codraw/workflow
codraw/open-api
codraw/cron-job
codraw/process
codraw/log
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony