Skip to content

Code Quality: Remove the global PHPStan type aliases - #14900

Closed
westonruter wants to merge 2 commits into
WordPress:trunkfrom
westonruter:fix/phpstan-remove-global-type-aliases
Closed

westonruter wants to merge 2 commits into
WordPress:trunkfrom
westonruter:fix/phpstan-remove-global-type-aliases

Conversation

@westonruter

@westonruter westonruter commented Oct 26, 2026 •

Copy link
Copy Markdown
Member

✅ Committed in r64756 (ecdec59).


This removes the two global PHPStan type aliases in tests/phpstan/base.neon, Maybe_Callable (added in r63451) and Block_Style_Properties (added in r63524), and replaces their uses with types that stay with the docblocks in src/.

Why

A typeAliases entry in base.neon is only defined for core's own analysis, but the docblocks that use it are read elsewhere too. The stubs generated from core (php-stubs/wordpress-stubs) keep each reference to an alias and lose its definition, so PHPStan reports an unknown type at every use for anyone analyzing against those stubs, or against core's source directly, unless they define each alias themselves. The aliases are not present when using a WordPress release package or WordPress/WordPress, since they only include src/.

This was raised by @IanDelMar in the review thread on Optional_Callback in #13890, which proposed a third global alias:

This requires every developer who scans core directly or uses a stubs file to also define Optional_Callback or include WordPress's entire base.neon file.

and later:

I was excited to see WordPress start adopting PHPStan because I expected it to reduce the maintenance burden for both wordpress-stubs and phpstan-wordpress. But type aliases add another layer to maintain.

Alternatives discussed there, such as wordpress-stubs expanding the aliases when generating the stubs, or phpstan-wordpress shipping their definitions, would each add ongoing maintenance downstream, and neither helps anyone who analyzes against core's source directly. Global aliases can also collide with aliases defined elsewhere, which the WP_ prefix suggested in that thread would only reduce.

The Gutenberg dependency

This now blocks Gutenberg, which is adding PHPStan in WordPress/gutenberg#66693. Since Gutenberg tracks core trunk, its analysis should use core trunk's types rather than those of the last WordPress release, so the plan there is to generate the stubs from a pinned core trunk commit with the wordpress-stubs generator (until wordpress-stubs offers a nightly pre-release from trunk). Generated from trunk, the stubs reference both aliases without defining them, and Gutenberg's analysis reports 106 false errors, mostly where a callback is passed to remove_filter() or remove_action().

With this change, stubs generated from this branch contain no reference to an undefined alias, and Gutenberg's analysis reports none of those errors, without Gutenberg defining anything itself. The same applies to the next wordpress-stubs release generated from a version of WordPress that has these docblocks, which would otherwise break the analysis of every project using it.

(Stubs generated from trunk also need php-stubs/wordpress-stubs#498, since the function map currently adds a second @phpstan-return to 152 docblocks where core trunk now has its own.)

Changes

  • Maybe_Callable is inlined at its seven uses, as callable|string|array{0: string|object, 1: string}, on remove_filter(), has_filter(), remove_action(), has_action(), _wp_filter_build_unique_id(), and the WP_Hook methods behind them. Most of the uses are functions, which cannot import an alias declared on a class.
  • Block_Style_Properties is declared with @phpstan-type on WP_Block_Styles_Registry, where four of its five uses are, along with the explanation of its shape that was in base.neon. WP_REST_Block_Types_Controller imports it with @phpstan-import-type. An alias declared on a class is kept in the generated stubs, as WP_Post's Data_Array and WP_Hook's Hook_Callback already are.
  • base.neon has a note in place of the aliases explaining why there are none, so that new aliases are declared on classes too.

The cost is that a type used by functions has to be repeated until PHPStan supports declaring an alias outside a class (phpstan/phpstan#9164). That applies to Optional_Callback in #13890 as well.

Testing

  • composer phpstan reports no new errors. The one error it does report, an unmatched baseline entry for $authors_dropdown in class-wp-posts-list-table.php, is reported on trunk as well.
  • At level 10, phpstan-diff reports no errors on the changed lines.
  • Stubs generated from this branch with the wordpress-stubs generator contain no reference to either alias, and declare Block_Style_Properties on WP_Block_Styles_Registry.

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

Use of AI Tools

AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 5.5
Used for: Replacing the aliases, verifying the change with PHPStan, generating stubs from this branch and analyzing Gutenberg against them, and drafting the commit message and this description. Reviewed by me.


This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.

🤖 Generated with Claude Code

The `typeAliases` in `tests/phpstan/base.neon` were global to core's own
analysis, but the docblocks in `src/` that used them are read elsewhere
too. The stubs generated from core keep the references and lose the
definitions, so anyone who analyzes against core, or against those
stubs, gets an unknown type where each alias was used, unless they
define it themselves.

Inline the `Maybe_Callable` union at its uses, which are mostly
functions, where a class alias cannot be imported. Declare
`Block_Style_Properties` with `@phpstan-type` on
`WP_Block_Styles_Registry`, which the stubs keep, and import it into
`WP_REST_Block_Types_Controller`. Leave a note in place of the aliases,
so that new ones are declared on classes too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Test using WordPress Playground

The changes in this pull request can previewed and tested using a WordPress Playground instance.

WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Some things to be aware of

  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

The note in place of the global type aliases says to declare an alias on
a class, which leaves a type used by functions to be repeated. Say that
this lasts until PHPStan supports declaring an alias with `@phpstan-type`
outside a class, and link the issue that tracks it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@westonruter
westonruter marked this pull request as ready for review October 26, 2026 21:21
@github-actions

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs.

Core Committers: Use this line as a base for the props when committing in SVN:

Props westonruter.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.


Props Bot commands

You can trigger Props Bot actions by commenting on this PR:

  • @propsbot add <username> to give props to a GitHub user. Requires write access.
  • @propsbot remove <username> to leave a user out of the props. Requires write access.
  • @propsbot refresh to refresh this list. Adding the props-bot label works too.

wporg-sync pushed a commit that referenced this pull request Oct 26, 2026
The `typeAliases` defined in `tests/phpstan/base.neon` only exist for core's own analysis, but the docblocks in `src/` that use them are read elsewhere too. A WordPress release package and the `WordPress/WordPress` repository only include `src/`, and the stubs generated from core (as used by `szepeviktor/phpstan-wordpress`) keep each reference to an alias while losing its definition. Anyone analyzing a plugin or theme against core then gets an unknown type at every use of an alias, unless they define each one themselves.

The `Maybe_Callable` union is now written out at each of its uses, which are mostly functions, where an alias declared on a class cannot be imported. The `Block_Style_Properties` shape is declared with `@phpstan-type` on `WP_Block_Styles_Registry`, which the generated stubs keep, and imported into `WP_REST_Block_Types_Controller`. A note in `base.neon` explains why new aliases should be declared on a class as well, at least until PHPStan supports declaring one outside a class.

Developed in #14900.
Follow-up to r63451, r63524.

Props westonruter, marian1.
See #65817.


git-svn-id: https://develop.svn.wordpress.org/trunk@64756 602fd350-edb4-49c9-b593-d223f7449a82
wporg-sync pushed a commit to WordPress/WordPress that referenced this pull request Oct 26, 2026
The `typeAliases` defined in `tests/phpstan/base.neon` only exist for core's own analysis, but the docblocks in `src/` that use them are read elsewhere too. A WordPress release package and the `WordPress/WordPress` repository only include `src/`, and the stubs generated from core (as used by `szepeviktor/phpstan-wordpress`) keep each reference to an alias while losing its definition. Anyone analyzing a plugin or theme against core then gets an unknown type at every use of an alias, unless they define each one themselves.

The `Maybe_Callable` union is now written out at each of its uses, which are mostly functions, where an alias declared on a class cannot be imported. The `Block_Style_Properties` shape is declared with `@phpstan-type` on `WP_Block_Styles_Registry`, which the generated stubs keep, and imported into `WP_REST_Block_Types_Controller`. A note in `base.neon` explains why new aliases should be declared on a class as well, at least until PHPStan supports declaring one outside a class.

Developed in WordPress/wordpress-develop#14900.
Follow-up to r63451, r63524.

Props westonruter, marian1.
See #65817.

Built from https://develop.svn.wordpress.org/trunk@64756


git-svn-id: http://core.svn.wordpress.org/trunk@63906 1a063a9b-81f0-0310-95a4-ce76da25c4cd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant