Weave 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

symplify/phpstan-rules

A set of 80+ practical PHPStan rules for checking clean architecture, logical errors, naming, namespace placement, visibility overrides, and Symfony, Doctrine, and PHPUnit best practices—useful for any PHP project, from legacy codebases to modern stacks.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture Fit

  • Pros:

    • Auto-Registration Still Intact: Release 14.19.0 preserves the extra.phpstan.includes model, so rule sets continue to register through phpstan/extension-installer without hand-maintained includes: blocks.
    • Expanded Single Control Plane: parameters.symplify now covers modern and collections in addition to the existing sets. This reinforces the package as a single PHPStan control plane for Laravel projects: one toggle block instead of multiple neon includes.
    • New Default-On Groups Fit Convention-Over-Configuration: modern and collections default to true, matching the package’s “sensible defaults with explicit opt-out” model. Teams that want a broad baseline get more coverage automatically.
    • Laravel-Relevant False-Positive Fix: CommandMustHaveAsCommandAttributeRule now skips Laravel commands (#351). This directly reduces noise for Laravel console commands that do not use Symfony’s #[AsCommand] attribute.
    • Noise Reduction via Removals: Removing ExplicitExpectsMockMethodRule, NoMockOnlyTestRule, NoRepositoryCallInDataFixtureRule, and NoDuplicateNonRepeatableAttributeRule drops overly specific or low-value checks, reducing rule-surface maintenance.
    • New Doctrine Typing Depth: The collections group adds strict Collection typing, generic docblocks, repository return types, and nullable getter checks. This is valuable for Laravel apps with Doctrine-backed modules, even though Eloquent remains the dominant ORM.
    • Test-Quality Rules Continue to Improve: MockedMethodReturnMustMatchNativeTypeRule catches mocked return-type mismatches. It belongs to the opt-in mocks set, so it does not silently expand the default test-quality surface.
    • Restored Optional Rule: ForbiddenNodeRule is restored as optional, preserving extensibility without forcing it on all users.
  • Cons:

    • Two New Default-On Sets Increase Upgrade Shock: modern: true and collections: true by default mean an upgrade from 14.17.x can surface a new wave of errors even if existing toggles were pinned. The toggle block must now include these new keys explicitly.
    • Removed Rules Are a Behavioural Change: Teams relying on ExplicitExpectsMockMethodRule, NoMockOnlyTestRule, NoRepositoryCallInDataFixtureRule, or NoDuplicateNonRepeatableAttributeRule lose that enforcement. This is not labelled breaking, but it changes analysis outcomes and may leave stale ignore patterns.
    • Rule-Set Membership Change: FormTypeClassNameRule moved into the naming set (#354). Projects that disabled or selectively enabled sets may see the rule appear or disappear unexpectedly.
    • collections Is Mostly Irrelevant to Eloquent-Only Apps: For Laravel projects without Doctrine, the new collections group adds configuration and analysis surface with little practical value. It should be disabled in the fast PR lane and in Eloquent-only repos.
    • NoPublicNonActionMethodInControllerRule May Collide with Laravel Controller Conventions: Laravel controllers commonly expose public helper methods or invokable patterns that are not Symfony route actions. The rule targets Symfony AbstractController, but its presence in the Symfony set warrants validation against Laravel controller patterns.
    • Parameter Semantics Keep Growing: The symplify.* matrix now has more keys, all defaulting mostly to true. Typos or omitted keys silently enable more than intended.
    • Laravel-Specific Gaps Persist: Still no native rules for Illuminate\Contracts, Nova, Fortify, Vapor, or Blade.

Integration Feasibility

  • Low Risk:

    • Composer Upgrade: composer require --dev symplify/phpstan-rules:^14.19 remains the primary integration step, assuming phpstan/extension-installer is present.
    • Zero-Include Setup: Manual includes of naming-rules.neon, static-rules.neon, doctrine-rules.neon, symfony-rules.neon, phpunit-rules.neon, and related files must still be removed to avoid duplicated-include failures.
    • Group-Level Rollout: The new modern and collections groups can be disabled explicitly during upgrade, then enabled one at a time. This keeps the incremental adoption model intact.
    • Laravel Command Noise Reduced: The Laravel-command skip in CommandMustHaveAsCommandAttributeRule lowers the chance of false positives in Laravel console suites.
  • Potential Challenges:

    • Pinning Must Now Include New Keys: A pre-14.19 toggle block pinned to the old effective set is incomplete. Add modern: false and collections: false before comparing against the pre-upgrade baseline.
    • Removed Rules Require Config Cleanup: Remove references to removed rules from custom rule lists, documentation, and ignoreErrors patterns. If reportUnmatchedIgnoredErrors is enabled, stale ignore patterns can fail CI.
    • Baseline Deltas May Be Downward: Because four rules were removed, the post-upgrade error count may drop even when nothing else changed. Treat any delta as expected only after accounting for removals.
    • collections Adoption Should Be Conditional: Enable only where Doctrine is actually used. Eloquent-only Laravel apps should keep it off to avoid unnecessary analysis cost and irrelevant findings.
    • modern Is Broad: The group bundles trait, reference, dynamic-name, and foreach-ception rules. It may flag legacy Laravel code patterns that are valid but unconventional, so enable it with a baseline or a dedicated cleanup sprint.

Technical Risk

  • Minimal:

    • Licensing/Compatibility: MIT, PHPStan-native, no Laravel internals dependency.
    • Documented Toggle Defaults: The release notes explicitly state that modern and collections are enabled by default, making the effective config auditable if teams read the notes.
    • Regression Fixes: Skips for #[AsDoctrineListener], traits, Laravel commands, and non-public array method calls reduce known false positives.
  • Mitigable Risks:

    • Expanded Default-On Error Surge: Higher than in 14.17.0 because two new groups are on by default. Mitigate by pinning modern: false and collections: false during the upgrade PR, then enabling deliberately.
    • Removed Rule Coverage Gap: Teams may believe a check still runs after it was removed. Mitigate by documenting the removed rules and reviewing any ignoreErrors entries that referenced them.
    • Stale Ignore Patterns: Removed rules can leave unmatched ignore messages. Mitigate by running PHPStan with reportUnmatchedIgnoredErrors enabled in CI and cleaning the config.
    • Rule-Set Membership Drift: FormTypeClassNameRule moving to naming can change which toggle controls it. Mitigate by updating the toggle-to-rule mapping in DEVELOPMENT.md.
    • Laravel Controller False Positives: NoPublicNonActionMethodInControllerRule may flag public helper methods. Mitigate by validating against representative Laravel controllers before enabling the Symfony set broadly.
    • Silent Under-Loading: Still the highest-severity failure if phpstan/extension-installer is absent. Keep the smoke check that intentionally violates a known rule.
    • Parameter Typos with True Defaults: More keys mean more chances to misspell a toggle and silently inherit true. Pin every key explicitly in shared presets.

Key Questions

  1. Baseline Pinning: Does the upgrade PR explicitly pin modern: false and collections: false alongside the existing toggles so the pre-upgrade error count is preserved?
  2. Removed Rule Reliance: Which teams or repos currently rely on the four removed rules, and do any ignoreErrors entries or docs reference them?
  3. Doctrine Presence: Which services actually use Doctrine ORM/DBAL? Only those should enable symplify.collections: true; Eloquent-only repos should keep it off.
  4. Modern Group Adoption: Do we enable symplify.modern: true as a cleanup initiative, or defer until legacy trait/reference/foreach patterns are triaged?
  5. Test-Quality Coverage: Do we opt into symplify.mocks: true now to gain MockedMethodReturnMustMatchNativeTypeRule, or defer until Mockery usage is reviewed?
  6. Laravel Controller Compatibility: Does NoPublicNonActionMethodInControllerRule flag valid Laravel public helper methods in our codebase, and should the Symfony set be scoped or ignored for controllers?
  7. Extension-Installer Guarantee: Is phpstan/extension-installer a hard requirement in the template repo and CI image, and how is auto-loading verified after every upgrade?
  8. CI Performance: With two more default-on groups, do we split a fast PR lane (naming + static, modern/collections/mocks/ctor off) from a nightly full lane?
  9. Config Ownership: Do we centralise the expanded toggle matrix in a shared Laravel PHPStan preset, or keep per-repo phpstan.neon files with pinned defaults?
  10. Upstream Contribution: Should Laravel-specific rules be contributed upstream now that group toggles are the preferred configuration surface, or kept as a local extension?

Integration Approach

Stack Fit

  • Native Compatibility:
    • PHPStan + Extension Installer: Auto-registration still depends on phpstan/extension-installer. Verify presence before removing manual includes.
    • PHPStan Levels: symplify.* toggles remain orthogonal to level:. Teams can keep level: 5 while gating modern, collections, mocks, and ctor independently.
    • Symfony Components: The symfony and symfonyConfig sets still apply to Laravel’s Symfony-based HTTP/routing layers. The new NoPublicNonActionMethodInControllerRule needs validation against Laravel controller patterns.
    • Doctrine ORM/DBAL: The doctrine set remains on by default, and collections now adds stricter Collection typing rules. These are valuable only in Doctrine-backed modules; Eloquent-only apps should disable collections in fast lanes.
    • PHPUnit/Pest: phpunit remains default-on. mocks remains opt-in, now including MockedMethodReturnMustMatchNativeTypeRule.
    • Rector: rector-rules.neon remains opt-in. PreferGenericTemplateOnSameUnionTypeRule is a Rector-only addition and does not affect PHPStan toggle behaviour.
  • Non-Native Considerations:
    • Laravel Controllers: NoPublicNonActionMethodInControllerRule is Symfony-oriented. Laravel controllers may expose public helpers; validate before enabling broadly.
    • Laravel Commands: The CommandMustHaveAsCommandAttributeRule Laravel-command skip is a direct compatibility improvement.
    • Blade Templates: PHPStan still does not analyse Blade; continue using nunomaduro/collision or barryvdh/laravel-ide-helper for that surface.
    • Removed Rules: No replacement is provided for the four removed rules. Teams relying on them must accept the coverage gap or add local custom rules.

Migration Path

  1. Phase 1: Upgrade and Config Cleanup

    • Bump the dependency:
      composer require --dev symplify/phpstan-rules:^14.19
      
    • Confirm phpstan/extension-installer is installed.
    • Remove manual includes of naming-rules.neon, static-rules.neon, doctrine-rules.neon, symfony-rules.neon, symfony-config-rules.neon, phpunit-rules.neon, complexity-rules.neon, configurable-rules.neon, mocks-rules.neon, ctor-rules.neon, and symplify-rules.neon from phpstan.neon.
    • Remove or update any references to the removed rules: ExplicitExpectsMockMethodRule, NoMockOnlyTestRule, NoRepositoryCallInDataFixtureRule, and NoDuplicateNonRepeatableAttributeRule.
    • Record a pre-upgrade baseline:
      vendor/bin/phpstan analyse --level=5 --error-format=json > baseline-before.json
      
  2. Phase 2: Pin the Expanded Toggle Matrix

    • Explicitly set every symplify.* toggle, including the new groups, to mirror the intended baseline:
      parameters:
          symplify:
              naming: true
              complexity: true
              configurable: true
              static: true
              symfony: true
              symfonyConfig: true
              doctrine: true
              phpunit: true
              mocks: false
              ctor: false
              modern: false
              collections: false
      
    • Re-run analysis and compare against baseline-before.json. A small downward delta is expected if the removed rules were previously active; any upward delta indicates an unpinned or newly active rule set.
  3. Phase 3: Incremental Enablement

    • Enable modern first if the team wants broader PHP modernization coverage; expect trait, reference, dynamic-name, and foreach-ception findings.
    • Enable collections only in Doctrine-backed services, not Eloquent-only repos.
    • Enable mocks when ready for MockedMethodReturnMustMatchNativeTypeRule and other mock-quality checks.
    • Enable ctor last; constructor-injection rules tend to produce broad churn in Laravel service classes.
    • Use PHPStan baselines (--generate-baseline) to absorb legacy violations without disabling whole groups.
  4. Phase 4: Documentation and Training

    • Update the toggle matrix to include modern and collections, their default values, and the rule families they contain.
    • Document the removed rules and their coverage implications.
    • Document the FormTypeClassNameRule move to naming.
    • Add Laravel-specific examples for the new rules where applicable, especially mocked return types and controller visibility.
    • Note that manual includes: of this package are deprecated by design and now cause duplicated-include errors.

Compatibility

  • Laravel Versions: Laravel 8+ on PHP 8.0+ with PHPStan ^1.x remains the practical baseline.
  • Tooling Conflicts:
    • PHPStan Duplicated Includes: Still the primary hard conflict; resolved by deleting manual includes.
    • Unmatched Ignored Errors: Removed rules can leave stale ignoreErrors patterns. Enable reportUnmatchedIgnoredErrors to catch them.
    • Rector: Run before PHPStan as before. rector-rules.neon remains opt-in and is unaffected by symplify.* toggles.
    • Pint/PHP-CS-Fixer: No change; style fixes can still disagree with rule suggestions.
    • Doctrine: collections rules are relevant only where Doctrine is used. They do not replace Eloquent-specific analysis.

Sequencing

  1. Pre-requisites: PHPStan configured; phpstan/extension-installer present; clean branch; pre-upgrade baseline captured.
  2. Upgrade PR: Version bump + removal of manual includes + expanded toggle block with modern: false and collections: false + cleanup of removed-rule references, in a single commit.
  3. Validation: Compare analysis output to the pre-upgrade baseline; account for expected deltas from removed rules; ensure no duplicated-include errors.
  4. Enablement PRs: One group per PR, ordered by value and risk. Suggested order: modern, collections only in Doctrine services, mocks, ctor.
  5. CI Hardening: Split fast/full lanes; add the extension-loader smoke check; enforce reportUnmatchedIgnoredErrors.
  6. Documentation: Publish the expanded toggle matrix, removed-rule notes, and the duplicated-include failure mode.

Operational Impact

Maintenance

  • Larger Toggle Surface: parameters.symplify now includes modern and collections, bringing the effective matrix to twelve keys. Fewer neon files remain, but the single block requires more deliberate pinning.
  • Upgrade Discipline Is More Important: Because new groups default to true, every minor bump must be reviewed for new defaults. Pin every key explicitly, including future-added keys, to avoid inheriting new enforcement silently.
  • Removed Rules Reduce Some Maintenance: Four overly specific checks are gone, which lowers the number of exceptions teams may need to manage. The trade-off is lost coverage and possible stale config.
  • Rule-Set Membership Changes: FormTypeClassNameRule moving to naming means the toggle-to-rule mapping must be maintained as a living document.
  • Version Pinning: Pin ^14.19 and review minor bumps as behaviour-changing changes due to default-on group additions and rule removals.

Support

  • Top Support Ticket: “Duplicated include” errors after upgrading — still a one-line fix but now more likely because teams may upgrade straight from pre-14.17 configurations.
  • Second Ticket: “Rules aren’t running” when phpstan/extension-installer is missing — still the highest-risk silent failure.
  • Third Ticket: “Why did this rule stop running?” after removal of ExplicitExpectsMockMethodRule, NoMockOnlyTestRule, NoRepositoryCallInDataFixtureRule, or NoDuplicateNonRepeatableAttributeRule.
  • Fourth Ticket: New modern/collections findings appearing on upgrade because the groups default to true.
  • Toggle Discoverability: Developers must know which symplify.* key controls the rule that flagged their code. The toggle-to-rules table must now cover modern, collections, and the moved FormTypeClassNameRule.
  • Doctrine Scope Confusion: Teams may enable collections in Eloquent-only repos and see little value or irrelevant guidance. Documentation should state the Doctrine-only relevance clearly.

Scaling

  • Per-Lane Granularity Improves: The expanded toggles allow a cheap PR lane (naming + static, with modern, collections, mocks, and ctor off) and a comprehensive nightly lane.
  • Monorepo/Service Fleet: A shared Laravel preset should pin the full twelve-key matrix once and distribute it, avoiding per-repo drift and accidental default inheritance.
  • Analysis Time: Default-on modern and collections add runtime on every invocation for teams that do not pin them off. PHPStan parallel and result cache help, but fast lanes should explicitly disable heavy or irrelevant groups.
  • Doctrine Services: Enable collections only in the subset of services with Doctrine; this keeps analysis cost proportional to actual ORM usage.

Failure Modes

  • Duplicated Includes (Deterministic): Upgrade without removing manual includes → CI hard fail. High visibility, low effort to remediate.
  • Silent Non-Loading: Missing phpstan/extension-installer → rules never execute; analysis “passes” while enforcing nothing. Highest-severity failure because it is invisible.
  • Expanded Default-On Error Spike: modern and collections default to true; an unpinned upgrade can surface a larger-than-expected error wave and block merged PRs mid-sprint.
  • Removed Rule Coverage Gap: Teams may believe mock-only checks, data-fixture repository checks, or duplicate-attribute checks still run. No replacement is provided.
  • Stale Ignore Patterns: Removed rules can leave unmatched ignoreErrors entries, causing CI failure when reportUnmatchedIgnoredErrors is enabled.
  • Parameter Typos: Misspelled symplify.* keys fall back to defaults, which are mostly enabled. With more keys, the chance of accidental over-enforcement rises.
  • Controller Rule False Positives: NoPublicNonActionMethodInControllerRule may flag Laravel public helper methods if the Symfony set is enabled broadly.
  • Doctrine Collection Noise: collections rules may produce findings in codebases that do not actually use Doctrine, or may be ignored where they would be valuable.

Ramp-Up

  • Slightly More Complex Than 14.17.0: Onboarding is still “require the package, confirm extension-installer, review the toggle block,” but the toggle block is larger and includes two new default-on groups.
  • Estimated Effort: ~2–3 hours for the upgrade, expanded pinning, removed-rule cleanup, and baseline comparison; ~30–60 minutes per additional group enabled; ~half a day for CI lane split and documentation updates.
  • Team Communication: Announce the new default-on modern and collections groups, the four rule removals, and the duplicated-include failure mode in the same release note that ships the upgrade. Include explicit guidance that collections is Doctrine-only and that Laravel-only repos should keep it disabled unless Doctrine is in use.
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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core