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

Getting Started

Minimal Steps

  1. Installation:

    composer require symplify/phpstan-rules --dev
    composer require phpstan/extension-installer --dev
    

    phpstan/extension-installer is now the primary integration path — the package registers its rule sets through extra.phpstan.includes, so nothing else needs to be added to composer.json.

  2. First Configuration (no includes): Since 14.17.0 the rule sets are auto-loaded. Do not add includes: for naming-rules.neon, static-rules.neon, symplify-rules.neon, modern-rules.neon, collections-rules.neon, etc. — that now produces duplicated-include errors in PHPStan. phpstan.neon only needs the toggles you care about:

    parameters:
        symplify:
            symfony: false
            symfonyConfig: false
            doctrine: false
    

    Anything you omit keeps its default (see the toggle table below). Note that since 14.19.0 a bare config like the one above now runs the new modern and collections groups too — they are on by default.

  3. First Use Case: Run PHPStan on a single file, then on a small directory, and read the rule class name in each error message before touching the config again:

    vendor/bin/phpstan analyse src/Controller/SomeController.php
    

    On a Doctrine project, start with an entity or repository: the collections group gives fast, high-signal feedback (Collection generics, repository return types).

Default toggle state (14.19.0):

Parameter Default Notes
symplify.naming true Rename-oriented checks; now also owns FormTypeClassNameRule
symplify.complexity true Structural / size checks
symplify.configurable true Rules that read their own arguments
symplify.static true Static analysis helpers, no framework needed
symplify.modern true New in 14.19.0 — trait, reference, dynamic-name, foreach-ception rules
symplify.collections true New in 14.19.0 — Doctrine Collection typing rules
symplify.symfony true Framework-specific; noisy outside Symfony
symplify.symfonyConfig true Validates YAML/JSON config files
symplify.doctrine true ORM-oriented checks
symplify.phpunit true Test-suite checks
symplify.mocks false Opt-in; slimmer since two mock rules were removed
symplify.ctor false Opt-in

config/rector-rules.neon is not auto-loaded and remains opt-in via an explicit includes: entry.


Implementation Patterns

Workflows

  1. Upgrade day (existing installs):

    • Delete every vendor/symplify/phpstan-rules/config/*.neon include from phpstan.neon, including symplify-rules.neon.
    • Run composer dump-autoload (extension-installer needs the refreshed autoloader to pick up the new extra.phpstan.includes).
    • Run PHPStan over the full codebase and diff the error count — on 14.19.0 expect a second jump beyond the 14.17.0 one, because modern and collections are newly enabled by default.
    • Clear stale ignores in the same commit: four rules were removed and several bugfixes suppress previously reported errors (see Gotchas).
  2. Progressive Rollout / Per-Project Profiles:

    • Turn off whole sets before turning off individual rules. A Laravel app typically starts with:
      parameters:
          symplify:
              symfony: false
              symfonyConfig: false
              doctrine: false
              collections: false
      
      collections only makes sense with Doctrine, so switch it off alongside doctrine on non-Doctrine codebases. Keep modern on — it is framework-agnostic and cheap to satisfy.
    • Keep two configs (phpstan.neon for src, a stricter one for tests) rather than toggling rule-by-rule in one file.
  3. Opting Into the Disabled Sets:

    • mocks and ctor are off by default; enable only when the codebase is already consistent about test doubles and constructor design:
      parameters:
          symplify:
              mocks: true
              ctor: true
      
    • mocks is narrower than it used to be (ExplicitExpectsMockMethodRule and NoMockOnlyTestRule were removed in 14.19.0), so re-measure before assuming it is still too noisy.
  4. Rule-Specific Arguments:

    • Toggling is per set; individual rule configuration still goes under services in your own config. Treat the symplify.* booleans as an on/off switch and use services/rules for arguments and severity only.
  5. Rector Pairing:

    • rector-rules.neon must still be included manually. Keep it in a separate phpstan-rector.neon that extends your base config, so the extra passes don't run on every local analysis:
      includes:
          - phpstan.neon
          - vendor/symplify/phpstan-rules/config/rector-rules.neon
      
    • 14.19.0 adds PreferGenericTemplateOnSameUnionTypeRule there — it is a rector rule, so it does nothing unless that include is present.

Integration Tips

  • CI/CD Pipeline:

    - name: PHPStan
      run: vendor/bin/phpstan analyse --level=5 --no-progress
    

    Because defaults are enabled, CI is now stricter than before on upgrade day — and stricter again with 14.19.0. Land the toggle config in the same PR as the composer bump.

  • IDE Integration: PHPStorm reads the same phpstan.neon, so the symplify.* toggles apply to real-time feedback automatically. No IDE-side setup beyond pointing at the config.

  • Baseline First, Rules Second: Generate phpstan-baseline.neon immediately after upgrading, then fix violations set by set by deleting baseline entries. With the new collections set this works especially well: generic docblocks on entities/repositories can be added class by class without blocking merges.

  • Doctrine Typing Sweep: Use collections as a one-off cleanup pass over src/Entity and src/Repository with the rest of the config unchanged:

    vendor/bin/phpstan analyse src/Entity src/Repository --no-progress
    

    Fix the getters/params/properties, then re-enable normal analysis.


Gotchas and Tips

Pitfalls

  1. Duplicated Includes:

    • The upgrade error to expect. Any leftover include of a bundled set (including symplify-rules.neon, and now modern-rules.neon/collections-rules.neon if you copied names from the release notes) now clashes with the auto-registered one. Remove the include; do not try to "win" by ordering.
  2. New Default Sets on 14.19.0:

    • modern and collections are enabled by default. collections fires on Doctrine mapping classes and will look like noise if you deliberately keep doctrine: false — turn collections: false off with it rather than baselining. modern fires broadly (traits, references, dynamic names, nested foreach) and is worth keeping on.
  3. Silent Extension-Installer Failures:

    • If no symplify.* errors appear and no set seems active, the extension was never registered: check that phpstan/extension-installer is installed and that composer.json does not have "allow-plugins" blocking it, then composer dump-autoload and vendor/bin/phpstan clear-result-cache.
  4. Disabling Is Explicit — Partial Config Does Not Reset Defaults:

    • Setting symplify: { nops: false } (typo) is not an error; the key is ignored and the set stays on. Only the exact documented keys take effect, so a typo looks like "the toggle doesn't work". Copy key names from the release notes rather than retyping.
  5. Rules Removed in 14.19.0 — Clean Up Your Ignores:

    • ExplicitExpectsMockMethodRule, NoMockOnlyTestRule, NoRepositoryCallInDataFixtureRule and NoDuplicateNonRepeatableAttributeRule are gone. Any baseline entries, ignoreErrors patterns or @phpstan-ignore-line comments targeting them become stale and trip reportUnmatchedIgnoredErrors. Grep your config for the rule class names/identifiers when upgrading.
  6. Bugfixes Can Invalidating Existing Suppressions:

    • NoAssertFuncCallInTestsRule now detects test classes via TestCase reflection and skips traits; ForbiddenArrayMethodCallRule allows array method calls on non-public methods; RequireQueryBuilderOnRepositoryRule skips traits; NoListenerWithoutContractRule skips #[AsDoctrineListener]; CommandMustHaveAsCommandAttributeRule skips Laravel commands; curl_* and array_walk left the forbidden-function list. Each of these removes errors you may have ignored for — expect a batch of unmatched-ignore failures, not just fewer errors.
    • Additionally, the 14.17.0 fix for PreferInterfaceInConstructorRule and Mailer transports still applies: drop any inline ignore you kept for it.
  7. mocks and ctor Off by Default:

    • Teams that previously enabled test-mock or constructor rules via manual includes will silently lose them after dropping the include. If you relied on them, add the explicit mocks: true / ctor: true toggles in the same commit — and re-check the set's contents, since two rules were removed from the mocking group.
  8. rector-rules.neon Is Not Auto-Loaded:

    • It stays opt-in by design, which means PreferGenericTemplateOnSameUnionTypeRule (new) and everything else in that file are inert without the include. Don't assume the upgrade wired it up.
  9. FormTypeClassNameRule Moved Sets:

    • It now lives in the naming group. If you had naming: false with configurable: true (or vice versa) to isolate it, your effective coverage changed after 14.19.0; re-run and diff rather than assuming the same toggles produce the same errors.
  10. Symfony-Set Noise:

    • symfony, symfonyConfig and doctrine are on by default and will fire on non-Symfony/Doctrine codebases. This includes NoPublicNonActionMethodInControllerRule, which now flags any public helper in a controller class. Turn the sets off up front instead of baselining hundreds of irrelevant errors.
  11. False Positives in Path-Based Rules:

    • File-path rules misbehave when analysis runs from a different working directory (CI containers, PHAR builds). Run PHPStan from the project root and exclude fixture/test directories rather than ignoring each violation.

Debugging

  1. Rule-Specific Errors:

    • Error messages carry the fully-qualified rule class name (e.g. Symplify\PHPStanRules\Rules\...). Search the README for that class before changing configuration, and check which set it belongs to so you know which symplify.* toggle controls it — the new rules are split across collections, modern, doctrine, symfony, naming and the opt-in mocks group.
  2. Verify What Is Actually Loaded:

    • vendor/bin/phpstan analyse -v plus vendor/bin/phpstan dump-parameters (or your own --debug run) show the resolved parameter tree; confirm symplify.* matches what you wrote rather than what you intended. This is the fastest way to confirm modern/collections really default to true in your install.
  3. Caching After Config Changes:

    • Toggles are read from the merged config; stale result cache makes changes look ineffective. vendor/bin/phpstan clear-result-cache after any symplify: edit — mandatory after a minor bump that adds sets.
  4. Ignoring Specific Violations:

    • Prefer ignoreErrors with a path and message pattern in phpstan.neon over per-line @phpstan-ignore-line; per-line ignores break on refactors and trigger unmatched-ignore errors, which is exactly the failure mode the 14.19.0 removals and bugfixes create.
  5. Generic Docblock Rules Need the Mapping Visible:

    • The Collection generics rules read Doctrine mapping attributes and existing docblocks. Excluding entity directories from analysis, or analysing a file in isolation without its use statements resolvable, hides or distorts the result. Analyse the whole src/ for a reliable count.

Extension Points

  1. Custom Rules:

    • Write your own rules and register them under rules: in your project config. Keep project-specific rules out of the bundled sets so a future release never changes their behaviour.
  2. Layered Configs:

    • Use one base phpstan.neon with the symplify.* profile for the app and includes:-based child configs (phpstan-tests.neon, phpstan-rector.neon) that only differ in toggles plus the opt-in rector-rules.neon.
  3. Severity, Not Deletion:

    • To soften a set during rollout, keep the toggle on and demote specific rules in rules: rather than disabling the whole set — you keep visibility without blocking merges. This is the documented preference upstream: prefer group toggles over per-rule switches, and reach for severity before deletion.
  4. Treat the Toggle Block as Versioned Config:

    • Defaults are the contract of the package, and they move: 14.19.0 added modern and collections as default-on groups. Own a symplify: block explicitly, even if it mirrors defaults, and review it in every upgrade PR so a silent default flip cannot change your CI outcome.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource