Make WordPress Core

Opened 2 months ago

Last modified 3 weeks ago

#64898 new task (blessed)

PHPStan code quality improvements for 7.1

Reported by: desrosj's profile desrosj Owned by:
Milestone: 7.1 Priority: normal
Severity: normal Version:
Component: General Keywords: has-patch has-unit-tests
Focuses: coding-standards Cc:

Description

This ticket is for various code quality issues and improvements surfaced via PHPStan.

Implementing PHPStan is tracked separately in #61175.

Previously:

Change History (26)

This ticket was mentioned in PR #11302 on WordPress/wordpress-develop by @Soean.


2 months ago
#1

  • Keywords has-patch added

This pull request makes a small change to the check_import_new_users function, simplifying its logic to directly return the result of the permission check.

Trac ticket: https://core.trac.wordpress.org/ticket/64898

This ticket was mentioned in PR #11303 on WordPress/wordpress-develop by @Soean.


2 months ago
#2

The url value is $tag->link unless '#' === $tag->link, then its #. Which is the same as $tag->link.
So we can simplify it and always use $tag->link.

Trac ticket: https://core.trac.wordpress.org/ticket/64898

#3 @SergeyBiryukov
2 months ago

In 62066:

Code Quality: Simplify tag URL assignment in wp_generate_tag_cloud().

This removes a redundant ternary that no longer affects the logic after the esc_url() call on the tag URL was moved to the output in an earlier revision.

Follow-up to [9518], [11383], [32996].

Props Soean.
See #64898.

@SergeyBiryukov commented on PR #11303:


2 months ago
#4

Thanks for the PR! Merged in r62066.

@SergeyBiryukov commented on PR #11302:


2 months ago
#5

Thanks for the PR! Merged in r62086.

This ticket was mentioned in PR #11340 on WordPress/wordpress-develop by @Soean.


8 weeks ago
#6

This pull request makes minor code cleanups across several files, removing unnecessary uses of the sprintf function when localizing or outputting static strings. These changes simplify the code and improve readability without affecting functionality.

Introduced in:

Trac ticket: https://core.trac.wordpress.org/ticket/64898

#7 @SergeyBiryukov
8 weeks ago

In 62167:

Code Quality: Unwrap sprintf() with one argument.

This removes unnecessary uses of the sprintf() function when localizing or outputting static strings. These changes simplify the code and improve readability without affecting functionality.

Props Soean.
See #64898.

@SergeyBiryukov commented on PR #11340:


8 weeks ago
#8

Thanks for the PR! Merged in r62167.

This ticket was mentioned in PR #11331 on WordPress/wordpress-develop by @Soean.


7 weeks ago
#9

This pull request makes minor code simplifications by removing unnecessary ternary operations and directly assigning boolean expressions. These changes make the code easier to read and maintain, but do not alter the underlying logic.

Trac ticket: https://core.trac.wordpress.org/ticket/64898

#10 @SergeyBiryukov
7 weeks ago

In 62173:

Code Quality: Simplify boolean assignments.

This makes minor code simplifications by removing unnecessary ternary operations and directly assigning boolean expressions. These changes make the code easier to read and maintain, but do not alter the underlying logic.

Props Soean.
See #64898.

@SergeyBiryukov commented on PR #11331:


7 weeks ago
#11

Thanks for the PR! Merged in r62173.

@Soean commented on PR #11429:


7 weeks ago
#13

Maybe we can use the PHPStan ticket: https://core.trac.wordpress.org/ticket/64898

#14 @SergeyBiryukov
7 weeks ago

In 62201:

Code Quality: Remove unused variable in WP_Block_Patterns_Registry.

Follow-up to [56805], [59101].

Props Soean, mukesh27.
See #64898.

@westonruter commented on PR #11429:


7 weeks ago
#15

This was committed by @SergeyBiryukov in r62201 (8510818).

This ticket was mentioned in PR #11692 on WordPress/wordpress-develop by @westonruter.


3 weeks ago
#16

  • Keywords has-unit-tests added

tl;dr: Adds a PHPStan parser-node visitor that bridges WordPress core's @global Type $varname PHPDoc convention to PHPStan's variable type resolution, eliminating ~3,800 false-positive mixed errors without touching any production code.


I use a local PHPStan configuration at level 10. This causes PHPStan to complain a _lot_, including about the use of globals like $wpdb. For code like this:

https://github.com/WordPress/wordpress-develop/blob/75b41314907d43bb111e22e305ba048bd4b90ec2/src/wp-includes/class-wp-network-query.php#L387

I get two errors from PHPStan:

  • phpstan: Cannot access property $site on mixed.
  • phpstan: Part $wpdb->site (mixed) of encapsed string cannot be cast to string.

This is in spite of the fact that the method has:

https://github.com/WordPress/wordpress-develop/blob/75b41314907d43bb111e22e305ba048bd4b90ec2/src/wp-includes/class-wp-network-query.php#L322

and

https://github.com/WordPress/wordpress-develop/blob/75b41314907d43bb111e22e305ba048bd4b90ec2/src/wp-includes/class-wp-network-query.php#L327

The issue is that PHPStan doesn't recognize this use of @global. It's a WordPress-specific thing. It does recognize this, however:

/** @var wpdb $wpdb */
global $wpdb;

While we could fix the issues by going throughout core and adding these @var tags, this would be extremely noisy and be of very little value. Instead, we can introduce a PHPStan extension for core which causes PHPStan to treat the @global annotations as aliases for inline @var annotations. This is what is implemented by this PR.

# Approach by Claude

Adds a custom parser node visitor, WordPress\PHPStan\GlobalDocBlockVisitor, that:

  1. Walks each FunctionLike node and parses any @global Type $name tags from its docblock.
  2. For every global $name; statement inside that function body, if $name matches a documented tag, attaches a synthetic /** @var Type $name */ doc comment to the global AST node.
  3. PHPStan's existing @var-on-global handling then assigns the documented type.

Behavior:

  • Functions without @global tags are untouched; their globals continue to resolve as mixed.
  • Globals not listed in the function's @global block are untouched; they continue to resolve as mixed.
  • Hand-written @var annotations already present on a global statement are respected and preserved.
  • Nested functions/closures get their own @global map (visitor uses a stack).

The visitor is registered as a phpstan.parser.richParserNodeVisitor service in tests/phpstan/base.neon and autoloaded via a new autoload-dev PSR-4 entry in composer.json mapping WordPress\PHPStan\ to tests/phpstan/. composer install (which runs composer dump-autoload) makes the class available to PHPStan automatically.

# Result

When running composer -- phpstan --configuration=phpstan.neon.dist --level=10:

  • Before: [ERROR] Found 40069 errors
  • After: [ERROR] Found 36300 errors

## Claude comparison

### Comparison summary

Trunk Branch Diff
------------------------------------------- ----: -----: --------:
Total errors (PHPStan totals) 40069 36300 -3769
Unique errors (file+line+id+msg) 39372 35705 -3667
Fixed by branch (in trunk, not branch) 4456
Introduced by branch (in branch, not trunk) 789

The fixed-vs-introduced asymmetry exists because the visitor narrows $wpdb etc. from mixed to wpdb, which both removes errors (the mixed.method() family) and exposes new ones (real type mismatches in wpdb method signatures, @var array injections that PHPStan wants array<...> for, etc.).

### Top fixed identifiers

1375 method.nonObject              -- $foo->method() on what was mixed
1040 property.nonObject            -- $foo->prop on what was mixed
 607 encapsedStringPart.nonString  -- "FROM $wpdb->posts" interpolations
 462 argument.type
 304 offsetAccess.nonOffsetAccessible
 188 binaryOp.invalid
 126 foreach.nonIterable
 119 return.type
  64 cast.int
  46 assignOp.invalid
  39 property.notFound
  32 method.notFound
  21 offsetAccess.invalidOffset
  15 assign.propertyType
   6 preInc.type

### Top fixed messages

304 Cannot call method prepare() on mixed.
233 Cannot access property $posts on mixed.
188 Part $wpdb->posts (mixed) of encapsed string cannot be cast to string.
126 Argument of an invalid type mixed supplied for foreach, only iterables are supported.
111 Cannot access offset string on mixed.
110 Cannot call method query() on mixed.
108 Cannot call method get_results() on mixed.
100 Cannot call method get_var() on mixed.
 82 Cannot access offset mixed on mixed.
 75 Cannot access property $comments on mixed.
 64 Cannot cast mixed to int.
 64 Cannot call method get_col() on mixed.
 59 Cannot call method update() on mixed.
 53 Cannot access property $options on mixed.
 52 Part $wpdb->comments (mixed) of encapsed string cannot be cast to string.
 51 Cannot call method delete() on mixed.
 44 Cannot access property $term_taxonomy on mixed.
 41 Cannot call method esc_like() on mixed.
 38 Cannot access property $postmeta on mixed.
 38 Part $wpdb->options (mixed) of encapsed string cannot be cast to string.
 27 Cannot access property $site on mixed.    ← your original case

The 4456 fixed errors all stem from globals (mostly $wpdb, $wp_query, $wp_locale, $wp_filter, etc.) becoming concretely typed where @global tags exist. Nothing was suppressed via baseline; these are real PHPStan errors that the visitor now resolves.

Trac ticket: https://core.trac.wordpress.org/ticket/64898

## Use of AI Tools

AI assistance: Yes
Tool(s): Claude Code
Model(s): Opus 4.7
Used for: Research and code writing

@westonruter commented on PR #11692:


3 weeks ago
#17

cc @justlevine, @apermo, @SergeyBiryukov

@westonruter commented on PR #11692:


3 weeks ago
#18

cc @szepeviktor

@westonruter commented on PR #11692:


3 weeks ago
#19

With 9fc7599, the error count is now brought down by another _three_ to 36,297 (from 36,300).

@szepe.viktor commented on PR #11692:


3 weeks ago
#20

@westonruter Please do not kill my package.

@westonruter commented on PR #11692:


3 weeks ago
#21

@szepeviktor Not my intention! 😅

If anything, this new PHPStan extension would reduce the need for php-stubs/wordpress-stubs. But it's just here for core. It seems like adding such @global support would be useful in your extension for themes and plugins to leverage?

@westonruter commented on PR #11692:


3 weeks ago
#22

With 38f2bf2, the total error count is brought down by another dozen to 36,285 (from 36,297). The regex was overengineered.

@szepe.viktor commented on PR #11692:


3 weeks ago
#23

It seems like adding such @global support would be useful in your extension for themes and plugins to leverage?

No. Some day WordPress will use PHP standards.

@westonruter commented on PR #11692:


3 weeks ago
#24

No. Some day WordPress will use PHP standards.

But wouldn't that kill your package? 😏

#25 @westonruter
3 weeks ago

In 62292:

Build/Test Tools: Honor @global docblock tags in PHPStan analysis.

This adds a PHPStan extension with a parser-node visitor that bridges WordPress core's @global Type $varname PHPDoc convention to PHPStan's variable type resolution, eliminating 3,784 spurious errors caused by globals resolving as mixed when on rule level 10 (out of 40,069 errors total, so a 9.4% reduction). This avoids the need to add /** @var Type $varname */ annotations with each global variable.

Developed in https://github.com/WordPress/wordpress-develop/pull/11692

Props westonruter, apermo, szepeviktor.
See #64898.

@westonruter commented on PR #11692:


3 weeks ago
#26

Committed in r62292 (9e0b63d).

Note: See TracTickets for help on using tickets.