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.
phpstan/extension-installer (introduced in 14.17.0) now extends to two new rule-set groups, modern and collections, both enabled by default. Teams get broader baseline enforcement without maintaining includes: blocks, strengthening the case for standardizing code quality across squads.symplify.* parameters. Default-on sets now include naming, complexity, configurable, static, symfony, symfonyConfig, doctrine, phpunit, plus the new modern and collections; mocks and ctor stay off. PMs can sequence quality initiatives by risk and team readiness — and, importantly, explicitly disable groups that don't fit a given repo (e.g., collections for non-Doctrine services).Collection usage, missing repository return types, nullable getters returning non-nullable types, controller helpers leaking as public "actions," and mocks returning values that contradict native return types. These are caught at analysis time rather than in review or production.collections group (4 rules) enforces generic docblocks and Collection return types on to-many associations. For products where entity/repository contracts underpin reporting, search, or API serialization, this meaningfully reduces "bare Collection" ambiguity and downstream type errors.NoReadonlyApiParamRule and NullablePropertyGetterMustReturnNullableRule codify subtle but real correctness constraints, useful for libraries or shared internal packages where reflection and nullability surprises are expensive.NoPublicNonActionMethodInControllerRule (Symfony), RepositoryMethodMustHaveReturnTypeRule (Doctrine), and the new modern group (trait, reference, dynamic-name, foreach-ception rules) support migration and modernization goals by enforcing current conventions.ExplicitExpectsMockMethodRule, NoMockOnlyTestRule, NoRepositoryCallInDataFixtureRule, NoDuplicateNonRepeatableAttributeRule), and FormTypeClassNameRule moved into the naming set. Fewer bespoke rules means less config to justify and maintain.phpstan.neon short and make trialing rules incremental.Adopt if:
MaximumIgnoredErrorCountRule) or enforce naming/convention consistency.Collection typing discipline across entities and repositories — a common source of latent type bugs.phpstan/extension-installer and remove manual includes: for this package's rule sets.Look elsewhere if:
modern group and NullablePropertyGetterMustReturnNullableRule are framework-agnostic, so Laravel teams gain some value — but symfony, symfonyConfig, doctrine, collections, and phpunit-specific rules assume a different stack. In practice, a Laravel team would run mostly with those groups disabled, which weakens the case versus a Laravel-native toolset (e.g., Larastan + Pint + Rector).Migration notes for 14.19.0 (stacking on 14.17.0):
modern and collections are enabled by default. Expect new PHPStan errors on first run after upgrade. Either budget a remediation pass or set symplify.modern: false / symplify.collections: false to stage adoption.ExplicitExpectsMockMethodRule, NoMockOnlyTestRule, NoRepositoryCallInDataFixtureRule, or NoDuplicateNonRepeatableAttributeRule, remove those entries. Inline rule identifier constants were also inlined into each rule (#348) — verify any custom references to those constants.FormTypeClassNameRule moved into the naming set; check per-rule overrides if you had customized it.curl_* and array_walk removed. If your policy depended on blocking curl_*, add an explicit custom rule — this is a reduction in coverage worth flagging.symplify-rules.neon to avoid duplicated-include failures; use symplify.* toggles. rector-rules.neon (including the new PreferGenericTemplateOnSameUnionTypeRule) remains opt-in.For Executives:
"This package automates a large set of code-quality checks for our Symfony/Doctrine stack, reducing defects and onboarding time. The latest release broadens coverage where bugs are expensive: it enforces strict typing on Doctrine collections and repository return types, correct nullability on getters, and prevents test mocks from returning values that contradict real types. Rollout stays low-risk — rule sets auto-load and are toggled with simple symplify.* parameters, so we can enable the newer checks per team rather than all at once. Two new groups switch on by default, so we should plan a short remediation pass on upgrade; four narrow rules were removed, which reduces maintenance. MIT-licensed and maintained by the Symplify team."
For Engineering Leaders: *"Symplify's PHPStan rules let us enforce best practices at scale without writing custom logic. 14.19.0 adds substance, not just config:
modern (traits, references, dynamic names, foreach-ception) and collections (Doctrine Collection typing — 4 rules covering getters, properties, params, and return docblocks).@api params must not be readonly; mocked willReturn() must match the mocked method's native return type; controllers must keep helpers private.FormTypeClassNameRule moved to the naming set — one less reason to hand-maintain per-rule overrides. Prefer group toggles over individual rule toggles.symplify.modern: false / symplify.collections: false if needed. curl_* was removed from the forbidden-function list, so that policy now needs a custom rule if we relied on it. Any config naming the removed rules must be cleaned up.symplify.* to match readiness."*For Developers:
"Think of it as a linter for PHPStan — it catches things your IDE and code review miss. 14.19.0 brings two new default-on groups: modern (trait/reference/dynamic-name/foreach issues) and collections, which stops you from using bare Collection without a generic docblock like @var Collection<int, Item>. It also flags repository methods without return types, nullable getters declared non-nullable, readonly on @api params, controller helpers that should be private, and mocks whose willReturn() value doesn't match the method's native return type. Config is still toggles in phpstan.neon; groups are encouraged over individual rules. Heads-up on upgrade: the new groups are on by default so expect new errors, four old rules were deleted (remove them from any configs), and FormTypeClassNameRule moved into the naming set. Run phpstan analyse locally and keep CI aligned."
How can I help you explore Laravel packages today?