In PHPStan 2, how do you ignore one error with @phpstan-ignore and an identifier, and how does that differ from ignoreErrors in phpstan.neon?
answer
- identifier, not the whole line
- // @phpstan-ignore argument.type (reason)
- own line = next line; trailing = same line
- ignoreErrors: message, identifier, path, count
- unused ignores are reported
basics
~20 sPut // @phpstan-ignore argument.type (reason) on or above the line, naming the error identifier; it silences only that error there. ignoreErrors in phpstan.neon matches by message regex or rawMessage, identifier, path and count across files.
solid answer
~50 s`@phpstan-ignore` takes an **error identifier**, shown next to each error in the default table output, for example `// @phpstan-ignore argument.type`. On a line of its own it applies to the next line; trailing code, it applies to its own line. Several identifiers are comma-separated, and a reason goes in parentheses: `// @phpstan-ignore argument.type (legacy API returns strings)`. Since 2.1.41, `reportIgnoresWithoutComments: true` makes the reason mandatory and bans the older `@phpstan-ignore-line` and `@phpstan-ignore-next-line`, which silence every error on a line. `ignoreErrors` in phpstan.neon is the config-side tool: entries match by `message` regex or `rawMessage`, `identifier` or `identifiers`, `path` or `paths` with `fnmatch` patterns, and an optional `count`. Both kinds are reported when they no longer match anything, because `reportUnmatchedIgnoredErrors` defaults to true. Some serious errors, such as parse errors or a missing parent class, cannot be ignored at all.
code
yaml · 11 linesparameters:
reportIgnoresWithoutComments: true
ignoreErrors:
-
identifier: missingType.iterableValue
paths:
- src/Legacy/*
-
rawMessage: 'Call to an undefined method Legacy\Client::send().'
path: src/Integration/Mailer.php
count: 1go deeper
Know that an error can be ignored inline with @phpstan-ignore followed by the identifier shown in PHPStan's output.
Explain the next-line versus same-line rule, reasons in parentheses, and the ignoreErrors keys: message or rawMessage, identifier, path and count.
Set a suppression policy: identifiers only, mandatory reasons via reportIgnoresWithoutComments, config ignores for categories and vendored code, and unmatched ignores kept on.
Decide how suppressions are reviewed and measured across teams so ignores stay rare, justified and removable.
## Error identifiers Rule errors in PHPStan 2 carry an **identifier** (2.0 made identifiers required even in custom rules), a stable dotted name for the kind of error: `argument.type`, `variable.undefined`, `property.notFound`, `missingType.iterableValue`, `varTag.nativeType`. The default `table` output shows it next to each error. Identifiers are what make precise ignores possible: you silence *this kind* of error, not everything on a line. ## Inline: @phpstan-ignore ```php // @phpstan-ignore argument.type (the legacy client passes numeric strings) $repository->find($request->get('id')); $mailer->send($legacyId); // @phpstan-ignore argument.type ``` The placement rules: 1. If the comment is the only thing on its line (besides whitespace), it applies to the **next** line. 2. If it follows code, it applies to **its own** line. 3. Any comment style works: `//`, `/* */` and `/** */`. 4. Several identifiers are separated by commas, and the same identifier can be repeated to ignore two errors of that kind on one line. 5. A reason goes in parentheses after the identifier. If nothing on that line produces the named error, PHPStan reports *No error with identifier argument.type is reported on line N*, so stale ignores do not accumulate. ## The older, blunter tags `@phpstan-ignore-line` and `@phpstan-ignore-next-line` silence **every** error on the line and take no identifier. They still work, but since PHPStan 2.1.41 you can forbid them: `reportIgnoresWithoutComments: true` reports any `@phpstan-ignore` without a reason in parentheses and disallows the two blunt tags entirely. ## Config: ignoreErrors | Key | Matches | |---|---| | `message` / `messages` | a regular expression on the error text | | `rawMessage` / `rawMessages` | the exact text as a plain string (2.1.24 and 2.1.40), no regex escaping | | `identifier` / `identifiers` | error identifiers | | `path` / `paths` | files, with `fnmatch()` patterns, relative to the config file | | `count` | how many occurrences are expected (with `message` and `path` only) | | `reportUnmatched` | override the global unmatched reporting for this entry | Examples of when config fits better than inline: - **A whole category you have decided to accept**, such as `identifier: missingType.iterableValue` while array value types are being added. In PHPStan 2 this replaces the removed `checkMissingIterableValueType: false` option. - **Generated or vendored code** inside the analysed paths, where editing the file is not an option. - **A PHPStan bug** you want to silence in one place until a fix ships. When `message` and `identifier` are both given, an error must match both. ## Finding the identifier to use You rarely need to guess an identifier: - The default `table` output prints it under each error, next to an ID-card icon. - The online playground on the PHPStan website shows it next to each reported message. - Custom error formatters receive it too, so a CI annotation can include it. - PHPStan's website keeps a browsable list of all error identifiers, grouped by prefix such as `argument.*` or `missingType.*`. Once you have it, `identifier:` in an `ignoreErrors` entry and `@phpstan-ignore` inline use the same string, so moving an ignore from code to config, or the reverse, is mechanical. ## Unmatched ignores `reportUnmatchedIgnoredErrors` defaults to `true`, and it covers both inline and config ignores. When the underlying code is fixed, or PHPStan gets smarter and stops reporting a false positive, the leftover ignore becomes an error. This keeps suppression honest, at the cost that a PHPStan upgrade that fixes a false positive can fail your build; the docs note that turning this option off prevents that class of upgrade failure. ## What cannot be ignored Some serious errors cannot be ignored and must be fixed to reach zero: the docs name autoloading issues, a parent class not found and parse errors. They block analysis of the affected code, so silencing them would hide far more than one finding. ## Choosing between the two - Use **inline `@phpstan-ignore` with an identifier and a reason** for individual, justified exceptions. It is visible in code review, tied to a line, and removed with the code. - Use **`ignoreErrors`** for categories, paths and third-party code. - Keep the **baseline** for the existing debt at adoption time, not for new exceptions.
- Why prefer @phpstan-ignore argument.type over @phpstan-ignore-next-line?The identifier form silences only that kind of error on that line, so a different error introduced later on the same line is still reported, and an unused ignore is flagged. The blunt tag hides every error on the line and cannot carry an identifier or a required reason.
- After a PHPStan upgrade, CI fails on an ignoreErrors entry you did not touch; why?The new version probably stopped reporting that error, for example a fixed false positive, so the entry no longer matches and `reportUnmatchedIgnoredErrors` reports it. Remove the entry, or set `reportUnmatched: false` on it if it matches only in some environments.
saying these in an interview costs you the question
- @phpstan-ignore without an identifier is the recommended form in PHPStan 2
- A trailing @phpstan-ignore applies to the next line
- Unused ignores are silently kept forever
- Parse errors can be ignored like any other error
- ignoreErrors paths resolve from the current working directory