Using PHPStan can improve the code quality of Drupal core.

This issue can be used to track progress on cleaning up all PHPStan errors found in Drupal Core.
PHPStan runs in different levels, the plan is to go up each level, and fix errors one level at a time.

PHPStan has a baseline to add, so we can go up a level, and by that moment disallow new errors from that level to enter the codebase, and add all the existing errors to the baseline so they can be fixed afterwards.

Start using phpstan

Add and configure phpstan in core

#3178534: Start running PHPStan on Drupal core (level 0)
#3259142: PHPStan commit check fails if a file is deleted
#3259353: Run full phpstan on composer change
#3259355: Always do a full phpstan analysis on DrupalCI

PHPStan ignored errors and files

To allow PHPStan to be added to core it was decided to ignore some files throwing problems and also ignore some errors. Those should be revisited.

excludePaths:
    # Skip settings.
    - ../*/settings*.php
    # Skip test fixtures.
    - */tests/fixtures/*.php
    # Below extends on purpose a non existing class for testing.
    - modules/system/tests/modules/plugin_test/src/Plugin/plugin_test/fruit/ExtendingNonInstalledClass.php
    # @todo files below need to be excluded as they prevent baseline generation.
    # Fixing them is a priority.
    - modules/link/tests/src/Kernel/LinkItemTest.php

  ignoreErrors:
    # new static() is a best practice in Drupal, so we cannot fix that.
    - "#^Unsafe usage of new static#"

    # Ignore common errors for now.
    - "#^Access to an undefined property#"
    - "#^Call to an undefined method#"
    - "#^Cannot unset offset#"
    - "#should return .* but return statement is missing#"
    - "#Drupal calls should be avoided in classes, use dependency injection instead#"
    - "#^Plugin definitions cannot be altered.#"
    - "#^Missing cache backend declaration for performance.#"
    - "#cache tag might be unclear and does not contain the cache key in it.#"
    - "#^Class .* extends @internal class#"

#3254966: PHPStan error LinkItemTest
#3259110: Fix undefined variables where files are included
#3259109: Fix 'Cannot unset offset' PHPStan L0 errors
#3259716: Replace usages of static::class . '::methodName' to first-class callable syntax static::method(...)

Upstream issues to followup

We already found some improvements / false positives. The should be fixed upstream and updated when a new release is available for phpstan / phpstan-drupal.

* Function twig_escape_filter not found #310

message: "#^Function twig_escape_filter not found\\.$#"
			count: 1
			path: lib/Drupal/Core/Template/TwigExtension.php

* BrowserTestBaseDefaultThemeRule ignore InstallerExistingConfigTestBase tests #311

message: "#^Drupal\\\\Tests\\\\BrowserTestBase\\:\\:\\$defaultTheme is required\\. See https\\://www\\.drupal\\.org/node/3083055, which includes recommendations on which theme to use\\.$#"
			count: 1
			path: modules/quickedit/tests/src/FunctionalJavascript/QuickEditJavascriptTestBase.php

* RenderCallbackRule causes error in PlaceholderGenerator #303

message: "#^The \"\\#lazy_builder\" expects a callable array with arguments\\.$#"
			count: 1
			path: lib/Drupal/Core/Render/PlaceholderGenerator.php

PHPStan level 0

Review the baseline and check for issues to be created.
https://git.drupalcode.org/project/drupal/-/blob/10.0.x/core/phpstan-bas...

One of the most occuring problems in the baseline is
Call to deprecated constant REQUEST_TIME (133 of 230 lines in baseline)
#2902895: [meta][no patch] Replace uses of REQUEST_TIME and time() with time service

PHPStan level 1 (and up)

Decide when to go a level up? Does the baseline needs to be fully clean?
#3190406: Update PHPStan to level 1

Comments

daffie created an issue. See original summary.

daffie’s picture

Issue tags: +PHPStan
andypost’s picture

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

mallezie’s picture

In the child issues there is already work done, and even some subissues split off which fixed things, spotted by phpstan, even it's not running on drupal core (yet).
I think in this main meta issue we should first discuss the plan of approach here, and link the correct issues. First step offcourse is to add phpstan, and then start fixing this. To break this up in smaller chunks, i would propose the following steps to doe.

  1. Add phpstan config to core (level 0). Enable it on CI, and in pre-commit-script, do not fix any problems, just add a baseline. This way we don't introduce any new phpstan level 0 errors. But can keep this part focussed on adding and running phpstan.Code for this can already be found in subissue, but might need some rescoping.
  2. Create a meta to fix all phpstan level 0 errors from the baseline. Some could probably be done in bulk, others might need seperate issue.
  3. When all (or most) of level 0 items are fixed, update phpstan to level 1, and include a new baseline
  4. Repeat step 2 and 3 till we're at level 8.

If this sounds a bit okay, i can work on cleaning up the subissues to follow this plan.

mondrake’s picture

i think #5.1 makes sense especially now that PhpStan 1.0 is out (actually, 1.1 already).

mondrake’s picture

Title: [META] Start running PHPStan on Drupal core (level 0) » [META] Start running PHPStan on Drupal core
mondrake’s picture

I suggest to start tagging 'phpstan' all issues related to this, and 'PHPStan-X' with X=level all issues specific to solving a set of a PHPStan level problems.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

mallezie’s picture

Version: 9.4.x-dev » 10.0.x-dev
mallezie’s picture

Issue summary: View changes
mallezie’s picture

Issue summary: View changes
mallezie’s picture

Issue summary: View changes
mglaman’s picture

I don't have the time to open a proper issue, but here's one we need to open. Replace usages of static::class . '::methodName' to [static::class, 'methodName'] array callable versus concatenation on static::class

That is why we have this error:

		-
			message: "#^\\#pre_render value 'non\\-empty\\-string' at key '0' is invalid\\.$#"
			count: 1
			path: lib/Drupal/Core/Render/Element/Pager.php

From:

  public function getInfo() {
    return [
      '#pre_render' => [
        static::class . '::preRenderPager',
      ],

It's just a PHPStan thing where static:class is handled a specify way for generics. So concatenating is weird. So let's use the proper array callable format for these scenarios and it will pass. See https://github.com/mglaman/phpstan-drupal/issues/301 for more background.

Other example: modules/big_pipe/tests/modules/big_pipe_regression_test/src/BigPipeRegressionTestController.php

mglaman’s picture

After reading the baseline, I am tracking the following three issues to resolve a few false-positives or bugs in phpstan-drupal

* Function twig_escape_filter not found #310
* BrowserTestBaseDefaultThemeRule ignore InstallerExistingConfigTestBase tests #311
* RenderCallbackRule causes error in PlaceholderGenerator #303

mondrake’s picture

Title: [META] Start running PHPStan on Drupal core » [META] Run PHPStan on Drupal core
Issue tags: +PHPStan-0

Thanks @mallezie for cleaning up this meta, it helps a lot!

Decide when to go a level up? Does the baseline needs to be fully clean?

IMHO not necessarily, but for sure we need to reduce the ignoreErrors patterns to a minimum - either solving them or moving them to baseline. Without that we will be potentially silently adding new failing code without knowing - whereas with baseline we would be able to take a picture and avoid new failures. Also for sure the baseline right now is too fat.

mallezie’s picture

Issue summary: View changes

Added issue for #14
#3259716: Replace usages of static::class . '::methodName' to first-class callable syntax static::method(...)
And added some stuff to the issue summary.

For moving up i fully agree currently our baseline is too fat. I think at least following requirements should be met:
* IgnoreRules and IgnoreErrrors are removed from the config (and fixed or in the baseline)
* The baseline should contain less than X items (first wild estimate for a number should be around 50, but depends on what is in the baseline). Could be a combination between less than X items in the baseline, and less then Y different messages in the baseline.

mondrake’s picture

Just checked, Level 1 would add over 800 more errors ATM.

andypost’s picture

mondrake’s picture

Status: Active » Fixed

I suggest we close this at this stage, PHPStan is already running on level 1.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.