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 paths 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 missing return type. Vortex comes with a pre-configured PHPStan ruleset for Drupal projects, so the analysis runs on every build without 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
The Ahoy command runs PHPCS, PHPStan and Rector in that order. The Docker Compose command runs PHPStan alone. To analyze the code, run 1 of the following commands:
- Ahoy
- Docker Compose
ahoy lint-be
docker compose exec cli vendor/bin/phpstan
Confirm that the analysis passed: PHPStan prints [OK] No errors.
PHPStan only reports errors and leaves your code unchanged. 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-specific rules from
mglaman/phpstan-drupal, which
phpstan/extension-installer loads automatically.
The phpVersion value in phpstan.neon, set to 80427, makes PHPStan
treat the code as PHP 8.4.27, the version the composer.json key
config.platform.php pins. PHPStan doesn't read that key, so update both
when you move to a new PHP version.
treatPhpDocTypesAsCertain is set to false because the types in doc
comments go out of date, so PHPStan relies on native type declarations.
The ignoreErrors list silences 2 errors that Drupal code can't avoid:
- Missing iterable value types in custom modules, custom themes and
tests/phpunit - Possibly undefined variables in the included settings files
PHPStan analyzes the following paths, which the paths list in
phpstan.neon sets:
web/modules/customweb/themes/customweb/sites/default/settings.phpweb/sites/default/includestestsscripts
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
Ignore violations
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's inline comments work 1 line at a time. To ignore errors in whole files, use the configuration:
- To leave files out of the analysis, add them to
excludePaths. - To silence 1 error in some files only, add
pathsto itsignoreErrorsentry, as in the preceding example.
The PHPStan issue Ignoring code blocks using PHPDocs explains why PHPStan has no block-level ignore.
To ignore 1 error on the next line, add a @phpstan-ignore comment with
the error identifier that PHPStan prints with 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 the next line, whatever its identifier, 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.
Ignore 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.