skip to content

In PHPStan 2, what are rule levels 0 to 10, and what do the main levels add as you move up?

level: juniorimportance: must knowfreq 58%

answer

  1. cumulative strictness dial
  2. default 0; --level or level: in neon
  3. 5: argument types; 6: missing typehints
  4. 8: nullable; 9: explicit mixed
  5. 10 (new in 2.0): implicit mixed

basics

~20 s

PHPStan's rule levels are a cumulative strictness dial from 0 (unknown classes, functions, wrong argument counts) to 10 (errors even for implicit mixed); each level adds checks to all lower ones, and max is an alias for the highest.

solid answer

~40 s

A rule level selects which checks PHPStan runs, and levels are cumulative: level 5 includes everything from 0 to 4. The default on the command line is 0. Level 0 reports unknown classes and functions, unknown methods on `$this`, wrong argument counts and always-undefined variables; 2 checks methods on all expressions and validates PHPDocs; 3 checks return types and property assignments; 5 checks argument types; 6 reports missing typehints; 7 partially wrong union types; 8 method calls and property access on nullable types; 9 is strict about explicit `mixed`. PHPStan 2.0 added level 10, which also treats a missing type as implicit `mixed` and reports unsafe use of it. `--level max` always means the highest level, which in 2.x is 10.

code

bash · 5 lines
bash
# run level 6 over two directories
vendor/bin/phpstan analyse --level 6 src tests

# always the highest level of the installed PHPStan (10 in 2.x)
vendor/bin/phpstan analyse --level max src

go deeper

for a junior

Know that levels run from 0 to 10, are cumulative, and that the default is 0. Be able to name one thing level 0 catches, such as an unknown class.

for a middle

Place the key checks: argument types at 5, missing typehints at 6, nullable access at 8, explicit mixed at 9, implicit mixed at 10.

for a senior

Explain why level 6 and level 10 cause big jumps on legacy code, and how --level on the CLI and level: in the config interact.

for a principal

Judge whether to pin a numeric level or use max, weighing automatic strictness against upgrade cost across many repositories.

## What a rule level is **PHPStan** is a static analyser for PHP: it reads your code without running it and reports errors such as calling an undefined method or passing a string where an `int` is declared. A **rule level** is how you choose how strict it is. In PHPStan 2 there are **11 levels, 0 to 10**, selected with `--level` (`-l`) on the command line or `level:` in `phpstan.neon`. Levels are **cumulative**. Internally each level's config file includes the one below it (`config.level6.neon` includes `config.level5.neon`, and so on), so running level 6 gives you every check from levels 0 to 5 plus the new ones. ## What each level adds | Level | Adds | |---|---| | 0 | unknown classes and functions, unknown methods called on `$this`, wrong number of arguments, always-undefined variables | | 1 | possibly undefined variables, unknown magic methods and properties on classes with `__call` and `__get` | | 2 | unknown methods on all expressions, not just `$this`; PHPDoc validation | | 3 | return types, types assigned to properties | | 4 | basic dead code: always-false `instanceof` and type checks, dead `else` branches, unreachable code after `return` | | 5 | types of arguments passed to functions and methods | | 6 | missing typehints | | 7 | partially wrong union types, such as calling a method that exists on only some types in a union | | 8 | calling methods and accessing properties on nullable types | | 9 | strict about explicit `mixed`: you may only pass it to another `mixed` | | 10 | also strict about implicit `mixed`, meaning values with no type at all (new in PHPStan 2.0) | ## The levels interviewers ask about most - **Level 5** is where argument type errors appear. Below it, `strlen(42)`-style mismatches go unreported, which surprises people who assume PHPStan checks types from the start. - **Level 6** is the jump that hurts on legacy code: every parameter, return and property without a type becomes an error, so the count often goes up by thousands. - **Level 8** reports calling a method on something that might be `null`, such as the result of a repository `find()` that returns `?User`. This is where many real production bugs are caught. - **Level 9 versus 10**: level 9 (internally `checkExplicitMixed`) only restricts values declared as `mixed`. Level 10 (`checkImplicitMixed`) extends that to values whose type is simply unknown, for example the return of a third-party function with no return type, or a parameter left untyped and hidden from level 6 by a baseline. ## Defaults and the max alias 1. With no config file and no `--level`, PHPStan runs **level 0**. 2. With a config file, the level must come from `--level` or the `level` parameter. If neither is set, PHPStan stops with *No rules detected* and explains the choices. 3. A `--level` on the command line wins over `level:` in the config. 4. `--level max` (or `level: max`) always selects the highest level the installed PHPStan has. In 2.x that is 10. The docs warn about the last one: pinning `max` means a PHPStan upgrade that adds a level, as 2.0 did with level 10, can turn a green build red. ## How the levels are meant to be used - The levels exist for **incremental adoption**. You start where the error count is manageable, reach zero, merge, and raise the level one step at a time. - A level is a floor for the whole analysed code, not a score. Two codebases at level 6 have the same checks enabled, not the same quality. - For strictness beyond level 10, PHPStan points to the separate `phpstan-strict-rules` extension, Bleeding Edge, and extra config options such as `checkUninitializedProperties`. In an interview, knowing where argument types (5), missing types (6), nullability (8) and `mixed` (9 and 10) come in is usually what separates someone who has used the levels from someone who has only heard of them.

  • Why can a codebase clean at level 9 show new errors at level 10?
    Level 9 only restricts values explicitly typed `mixed`. Level 10 treats values with no type at all, such as returns from untyped third-party functions or parameters whose missing types were baselined, as implicit `mixed` and reports unsafe operations on them.
  • What happens if phpstan.neon exists but sets no level and you pass no --level?
    PHPStan stops with a 'No rules detected' message. The default level 0 applies only when no config file is used; with a config you must set `level` in it or pass `--level`, or declare a custom ruleset with `customRulesetUsed: true`.
  • Is --level max a good setting for CI?
    It keeps you at the strictest level automatically, but the docs warn it can make PHPStan upgrades expensive: when a new major release adds a level or new checks at the top, CI turns red until the new errors are fixed. Pinning a number makes upgrades a separate, planned step.

saying these in an interview costs you the question

  • Level 0 already checks argument types against declarations
  • Each level replaces the previous one's checks
  • Level 9 is the highest level in PHPStan 2
  • The default level is max when no level is given
  • Level 10 is about coding style, not types