Skip to main content
Version: v1

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 lint-be

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

note

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/custom
  • web/themes/custom
  • web/sites/default/settings.php
  • web/sites/default/includes
  • tests
  • 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

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 paths to its ignoreErrors entry, 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.

➡️ See Continuous integration > Ignore tool failures