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

Phpstan Rules Laravel Package

shipmonk/phpstan-rules

40 super-strict PHPStan rules from ShipMonk to plug gaps in extra-strict setups. Install via Composer, include rules.neon, then enable/disable or tune rules per-project. Targets tricky PHP edge cases like unsafe comparisons, casts, arrays, enums and more.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:
    composer require --dev shipmonk/phpstan-rules
    
  2. Enable rules in phpstan.neon:
    includes:
        - vendor/shipmonk/phpstan-rules/rules.neon
    
  3. Run PHPStan:
    vendor/bin/phpstan analyse
    

First Use Case: Enforcing Strict Typing

Start with enforceNativeReturnTypehint and enforceClosureParamNativeTypehint to catch missing type hints in methods and closures. These rules align with modern PHP practices and reduce runtime type errors.


Implementation Patterns

1. Progressive Enforcement

  • Start small: Enable one or two rules (e.g., forbidCast or forbidArithmeticOperationOnNonNumber) and fix violations before adding more.
  • Team alignment: Use classSuffixNaming to enforce naming conventions (e.g., *Test for test classes) and reduce ambiguity in autoloading.

2. Rule-Specific Workflows

  • enforceEnumMatch: Replace exhaustive if-else chains for enums with match expressions. Configure PHPStan to fail on missing cases:
    parameters:
        shipmonkRules:
            enforceEnumMatch: true
    
  • enforceReadonlyPublicProperty: Gradually migrate public properties to readonly (PHP 8.1+). Exclude properties with default values if needed:
    parameters:
        shipmonkRules:
            enforceReadonlyPublicProperty:
                excludePropertyWithDefaultValue: true
    

3. Integration with CI

  • Fail builds on violations: Add PHPStan to your CI pipeline with strict level:
    # .github/workflows/phpstan.yml
    jobs:
      phpstan:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          - run: composer install
          - run: vendor/bin/phpstan analyse --level=max --error-format=github
    

4. Custom Rule Configuration

  • Override defaults: Use ! to replace default configurations (e.g., whitelist allowed casts):
    parameters:
        shipmonkRules:
            forbidCast:
                blacklist!: ['(bool)', '(int)']  # Only allow (bool) and (int) casts
    
  • Disable specific rules: Opt out of opinionated rules like backedEnumGenerics if not using generics:
    parameters:
        shipmonkRules:
            backedEnumGenerics:
                enabled: false
    

5. Pair with PHPStan Native Rules

  • Combine with PHPStan’s built-in rules (e.g., reportAnyTypeWideningInVarTag) for lists:
    parameters:
        reportAnyTypeWideningInVarTag: true
        shipmonkRules:
            enforceListReturn: true
    

Gotchas and Tips

Pitfalls

  1. False Positives in enforceEnumMatch:

    • Rule may flag elseif chains that are intentionally exhaustive (e.g., for legacy code). Use @phpstan-ignore-next-line to suppress:
      // @phpstan-ignore-next-line
      elseif ($enum === MyEnum::LegacyCase) { ... }
      
    • Fix: Refactor to match or document why exhaustive checks are needed.
  2. forbidCheckedExceptionInCallable Overreach:

    • Rule blocks checked exceptions in closures, even if they’re caught later. Use @param-immediately-invoked-callable to whitelist:
      /** @param-immediately-invoked-callable $callback */
      public function execute(callable $callback): void { ... }
      
  3. enforceIteratorToArrayPreserveKeys Breaking Changes:

    • Rule requires explicit $preserve_keys in iterator_to_array(). Update all calls, even if you’re confident about the default behavior.
  4. BackedEnum Generics Requires Stub Files:

    • backedEnumGenerics does nothing without a custom stub file. Follow the ShipMonk guide to set up generics.
  5. PHP Version Mismatches:

    • Rules like enforceReadonlyPublicProperty or enforceNativeReturnTypehint are ignored on PHP <8.1. Ensure your phpstan.neon targets the correct PHP version:
      phpVersion: '8.2'
      

Debugging Tips

  • Isolate Rule Violations: Temporarily disable all rules except one to debug:
    parameters:
        shipmonkRules:
            enableAllRules: false
            enforceNativeReturnTypehint:
                enabled: true
    
  • Check Rule-Specific Configs: Some rules (e.g., forbidCheckedExceptionInCallable) require additional PHPStan configs (e.g., exceptions.checkedExceptionClasses). Verify your phpstan.neon includes:
    parameters:
        exceptions:
            checkedExceptionClasses:
                - App\Exceptions\RuntimeException
    
  • Use --error-format=json: For programmatic analysis, parse JSON output to identify rule-specific issues:
    vendor/bin/phpstan analyse --error-format=json | jq '.files[] | select(.ruleSet == "shipmonk/phpstan-rules")'
    

Extension Points

  1. Custom Rule Logic:

    • Extend existing rules by subclassing PHPStan\Rules\Rule and overriding methods. Example:
      // app/Rules/CustomRule.php
      use PHPStan\Rules\Rule;
      use PHPStan\Rules\RuleErrorBuilder;
      
      class CustomRule implements Rule {
          public function getNodeTypeNames(): array { return ['Php\Function_']; }
      
          public function processNode(Node $node): array {
              if ($node instanceof Php\Function_) {
                  return [$this->buildError($node)];
              }
              return [];
          }
      
          private function buildError(Node $node): RuleErrorBuilder {
              return RuleErrorBuilder::message('Custom rule violation')
                  ->onNode($node)
                  ->build();
          }
      }
      
    • Register in phpstan.neon:
      services:
          - App\Rules\CustomRule
      
  2. Dynamic Rule Configuration:

    • Use PHPStan\Analyser\Scope to conditionally enable/disable rules based on class/method names:
      use PHPStan\Analyser\Scope;
      
      class DynamicRule implements Rule {
          public function processNode(Node $node, Scope $scope): array {
              if ($scope->getClassReflection()?->getName() === 'App\Services\LegacyService') {
                  return []; // Skip for legacy classes
              }
              return [$this->buildError($node)];
          }
      }
      
  3. Whitelisting Exceptions:

    • For rules like forbidCast, use ignoreErrors in phpstan.neon to exclude specific files/classes:
      ignoreErrors:
          - '#^Class .* contains forbidden cast$#'
          - 'app/Legacy/Casts.php'
      

Performance Quirks

  • Rule Order Matters: Place stricter rules (e.g., forbidArithmeticOperationOnNonNumber) before broader ones (e.g., enforceNativeReturnTypehint) to avoid redundant checks.
  • Cache Invalidation: Clear PHPStan’s cache after adding new rules:
    vendor/bin/phpstan clear-cache
    
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