Skip to main content
Version: v2

PHPStan - PHP static analysis tool

The PHPStan project describes the tool as follows:

PHPStan focuses on finding errors in your code without actually running it. It catches whole classes of bugs even before you write tests for the code. It moves PHP closer to compiled languages in the sense that the correctness of each line of the code can be checked before you run the actual line.

PHPStan checks every code path, including the ones your tests never reach. It reports problems such as a call to a method that doesn't exist, an argument of the wrong type, or a function that doesn't declare its return type. Vortex comes with a pre-configured PHPStan ruleset for Drupal projects, so the analysis runs on every build without any setup.

This page is for developers who write PHP in a Vortex project. It shows how to run PHPStan, what the shipped configuration analyzes, and how to ignore an error you can't fix. For PHPStan itself, see the PHPStan user guide.

Usage​

ahoy lint-be runs PHPCS, PHPStan, and Rector in that order, while the Docker Compose command runs PHPStan alone. To analyze the code, run 1 of the following commands:

ahoy lint-be

Confirm that the analysis passed: PHPStan prints [OK] No errors.

note

PHPStan doesn't change your code: it only reports errors. Rector fixes some of the same problems automatically, such as missing type declarations.

➡️ See Rector

Configuration​

See the PHPStan configuration reference.

All global configuration lives in the phpstan.neon file.

The analysis runs at level 7 with the Drupal context in mind, thanks to mglaman/phpstan-drupal, which phpstan/extension-installer loads automatically. It treats the code as PHP 8.4.27: the phpVersion value of 80427 matches the composer.json key config.platform.php. PHPStan doesn't read that key, so update both when you move to a new PHP version.

treatPhpDocTypesAsCertain is set to false, so PHPStan relies on native type declarations rather than the types in doc comments, which go out of date. The ignoreErrors list silences the errors that Drupal code can't avoid: missing iterable value types in custom modules, custom themes, and tests/phpunit, and possibly undefined variables in the included settings files.

Targets include custom modules and themes, settings, tests, and scripts.

To add or remove targets, edit the paths and excludePaths lists in phpstan.neon:

parameters:
paths:
- path/to/dir_or_file
excludePaths:
- path/to/exclude/all_dir_files/*
- path/to/exclude/a_file.php

Ignoring​

To ignore an error across the project, add it to ignoreErrors in the phpstan.neon file:

parameters:
ignoreErrors:
- # Comment about why this rule is excluded.
# 'message' is a regular expression with `#` as begin and end delimiters.
message: '#.*no value type specified in iterable type array.#'
paths:
- path/to/exclude/all_dir_files/*
- path/to/exclude/a_file.php

PHPStan has no comment that ignores a whole file, 1 rule across a file, or a block of code: inline suppression works 1 line at a time. To skip files, use the configuration instead. Add them to excludePaths to leave them out of the analysis, or add paths to an ignoreErrors entry, as in the preceding example, to silence that error in those files only. For why PHPStan has no block-level ignore, see the PHPStan issue Ignoring code blocks using PHPDocs.

To ignore 1 error on the next line, add a @phpstan-ignore comment with the error identifier that PHPStan prints alongside the error:

// @phpstan-ignore variable.undefined
echo $title;

To ignore an error on the same line instead, add the comment at the end of that line.

To ignore every error on a line, add this comment on the line before it:

// @phpstan-ignore-next-line
$a = 1;

Continuous integration​

PHPStan runs in the lint job of the continuous integration pipeline and fails the build on violations.

Ignoring failures​

To let the build pass anyway, set the VORTEX_CI_PHPSTAN_IGNORE_FAILURE CI variable to 1. PHPStan still runs and prints every error in the job log, so you can see what you're letting through.

➡️ See Continuous integration > Ignore tool failures