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 detects unused PHP code: dead methods, properties, constants, and enum cases. Finds dead cycles and transitive dead members, can flag dead tested code, supports popular frameworks (e.g., Symfony), and offers customizable usage providers with optional auto-removal.

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 Analyze your entire codebase (including tests):

    vendor/bin/phpstan analyse --level=max
    

    Ensure --level=max to catch all potential dead code.

  3. First Use Case Review the output for unused methods, properties, or constants. Example:

    Unused App\Service\UserService::legacyMethod
    

Implementation Patterns

Daily Workflow

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

    vendor/bin/phpstan analyse --error-format=github --generate-baseline
    

    Use --generate-baseline to ignore new errors temporarily.

  2. CI/CD Pipeline Add to your CI (e.g., GitHub Actions):

    - name: Run Dead Code Detection
      run: vendor/bin/phpstan analyse --error-format=checkstyle
    
  3. Iterative Cleanup

    • Fix one issue at a time (e.g., remove a dead method).
    • Re-run phpstan to validate changes.
    • Use --removeDeadCode for automated cleanup (caution: review changes first):
      vendor/bin/phpstan analyse --error-format=removeDeadCode
      

Integration Tips

  • Symfony/Laravel Projects Ensure phpstan/phpstan-symfony is installed for framework-specific detection:

    composer require --dev phpstan/phpstan-symfony
    

    Configure container paths in phpstan.neon:

    parameters:
        shipmonkDeadCode:
            usageProviders:
                symfony:
                    containerXmlPaths:
                        - var/cache/dev/App_KernelDevDebugContainer.xml
    
  • Test-Only Usages Exclude test usages to avoid false positives:

    parameters:
        shipmonkDeadCode:
            usageExcluders:
                tests:
                    enabled: true
    
  • Custom Providers Extend detection for project-specific logic (e.g., custom attributes):

    // src/UsageProviders/CustomAttributeProvider.php
    class CustomAttributeProvider implements MemberUsageProvider {
        public function getUsages(Node $node, Scope $scope): array {
            if ($node instanceof Attribute && $node->name->toString() === '[UsedInMyFramework]') {
                return [new ClassMethodUsage(..., new ClassMethodRef('App\Entity\User', 'customMethod'))];
            }
            return [];
        }
    }
    

    Register in phpstan.neon:

    services:
        - App\UsageProviders\CustomAttributeProvider{tags: ['shipmonk.deadCode.memberUsageProvider']}
    

Gotchas and Tips

Pitfalls

  1. False Positives in Dynamic Code

    • Issue: Methods called via call_user_func(), ReflectionMethod, or dynamic strings (e.g., $class::$method()) may be misclassified.
    • Fix: Use ReflectionBasedMemberUsageProvider to whitelist dynamic calls:
      class DynamicCallProvider extends ReflectionBasedMemberUsageProvider {
          public function shouldMarkMethodAsUsed(ReflectionMethod $method): ?VirtualUsageData {
              return VirtualUsageData::withNote('Dynamic call detected');
          }
      }
      
  2. Transitive Dead Code Overload

    • Issue: Enabling reportTransitivelyDeadMethodAsSeparateError floods output with cascading errors.
    • Fix: Keep it disabled (false) unless debugging specific cycles:
      parameters:
          shipmonkDeadCode:
              reportTransitivelyDeadMethodAsSeparateError: false
      
  3. Test Excluder Misconfiguration

    • Issue: Excluding test usages may hide legitimate test coverage.
    • Fix: Verify excluded usages are truly test-only:
      vendor/bin/phpstan analyse --error-format=github --debug
      
  4. Automatic Removal Risks

    • Issue: --removeDeadCode may delete critical logic if misconfigured.
    • Fix: Test in a branch first and review diffs:
      git diff > dead-code-changes.diff
      

Debugging Tips

  • Isolate Issues Use --focus-file to analyze specific files:

    vendor/bin/phpstan analyse --focus-file=src/Service/UserService.php
    
  • Inspect Usage Origins Enable debug mode to trace usage sources:

    parameters:
        shipmonkDeadCode:
            debug: true
    
  • Custom Error Formatting Generate IDE-friendly output (e.g., for PHPStorm):

    vendor/bin/phpstan analyse --error-format=json --output=phpstan-dead-code.json
    

Extension Points

  1. Override Default Detection Disable specific member types (e.g., constants) in phpstan.neon:

    parameters:
        shipmonkDeadCode:
            detect:
                deadConstants: false
    
  2. Whitelist Methods Use MemberUsageExcluder to ignore known false positives:

    class WhitelistExcluder implements MemberUsageExcluder {
        public function shouldExclude(ClassMemberUsage $usage, Node $node, Scope $scope): bool {
            return $usage->getClassMethodRef()->getMethodName() === 'getLegacyData';
        }
    }
    
  3. Leverage PHPStan Levels Run with --level=8 for stricter checks (but slower):

    vendor/bin/phpstan analyse --level=8
    

Laravel-Specific Quirks

  • Route/Event Listeners Ensure phpstan/phpstan-symfony is configured for Laravel’s service container:

    parameters:
        symfony:
            containerXmlPath: bootstrap/cache/services.php
    
  • Eloquent Observers/Factories Dead code in boot() or define() methods may be missed if not analyzed transitively. Enable:

    parameters:
        shipmonkDeadCode:
            detect:
                deadMethods: true
    
  • Artisan Commands Commands using #[Command] are detected, but ensure their classes are autoloaded in composer.json:

    "autoload-dev": {
        "psr-4": { "App\\Console\\": "app/Console/" }
    }
    
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport
twbs/bootstrap4