Skip to content

Build/Test Tools: Update PHPStan to 2.3.0 and replace the deprecated result cache meta extension - #14089

Closed
westonruter wants to merge 2 commits into
WordPress:trunkfrom
westonruter:update/phpstan-2.3
Closed

westonruter wants to merge 2 commits into
WordPress:trunkfrom
westonruter:update/phpstan-2.3

Conversation

@westonruter

@westonruter westonruter commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

✅ Committed in r64237 (ec8bf88).


Updates PHPStan to 2.3.0 (blog post) and phpstan/phpstan-phpunit to 2.1.1, which requires PHPStan 2.3. It then moves the bundled hook documentation tooling off the API that 2.3.0 deprecates.

Upgrade

  • Baselines are regenerated. 12 variable.undefined entries no longer match, because the rewritten engine now sees those variables are always defined.
  • WP_HTML_Processor::run_adoption_agency_algorithm() gains a greater.alwaysTrue and a greaterOrEqual.alwaysFalse baseline entry. Every path through its outer loop body either returns or calls bail(), which never returns, so the loop never runs a second time and its counters never change. PHPStan 2.3 now builds a loop's back edge only from reachable continue statements (Build a loop's back edge from its continue statements when the body end is unreachable phpstan/phpstan-src#6420), so it reports both comparisons as constant. The loop is scaffolding for parts of the algorithm that are not yet supported, so the errors are baselined as work still to do, not added to the permanent ignore list.

Replace the deprecated ResultCacheMetaExtension

2.3.0 deprecates ResultCacheMetaExtension in favor of dependencies declared on the scope. A changed meta hash discards the whole result cache, while a declared dependency re-analyzes only the files that declared it. HookDocsResultCacheMetaExtension folded two hashes into the cache key, and both are now handled another way:

  • Inherited hook docblocks. Resolving a "This filter is documented in <file>" reference now calls trackFileDependency() on each candidate path it tests. Editing a canonical docblock therefore re-analyzes only the files that reference it. Candidates that do not exist are tracked too, because creating one would change which file the reference names. This also removes a scan of wp-admin, wp-includes and the bundled themes that ran on every analysis.
  • The extension sources themselves. PHPStan 2.3 already runs a full analysis when the source of any registered extension or bootstrap file changes (-vv reports "Result cache not used because extension file … hash does not match"), so this hash was redundant.

The extension, its base.neon registration and the hashing helpers in HookDocBlock are removed. The rules and the apply_filters() return type extension now document their scope as Scope&DependencyTracker, which is what PHPStan passes them.

To test the tracking, a @param was added to the canonical the_title docblock in wp-includes/post-template.php with a warm cache. 22 files were re-analyzed, and every call site that inherits that docblock reported the parameter-count mismatch.

Checked, no change needed

  • The currentPhpVersionSimpleParser override in base.neon, which the README says to check after an upgrade, still connects to 2.3.0's parser setup, since cachedSimpleParser wraps it.
  • The two reportUnmatched: false entries in phpstan.neon.dist (substr_compare() and ValueError in @throws) still match.
  • Unused-variable detection and inference for closures and static variables are bleeding edge only, which the dist configuration does not include.

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: Performing the upgrade, reviewing the release notes and the new result cache APIs, implementing the dependency tracking, verifying it, and drafting this description.


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

westonruter and others added 2 commits October 7, 2026 13:58
phpstan-phpunit 2.1 requires PHPStan 2.3, so the two move together.

The baselines are regenerated for what the new release reports
differently:

* 12 `variable.undefined` entries no longer match, as the rewritten
  engine now sees these variables are always defined.
* `WP_HTML_Processor::run_adoption_agency_algorithm()` gains a
  `greater.alwaysTrue` and a `greaterOrEqual.alwaysFalse` entry. Every
  path through its outer loop body returns or calls `bail()`, which
  never returns, so the loop cannot iterate twice and its counters
  never move. PHPStan 2.3 now builds the loop's back edge only from
  reachable `continue` statements and so reports the comparisons as
  constant. The loop is scaffolding for the parts of the algorithm that
  are not yet supported, so this is baselined as work to do rather
  than ignored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PHPStan 2.3 deprecates `ResultCacheMetaExtension` in favor of
dependencies declared on the scope, which re-analyze only the files
that declared them instead of discarding the whole result cache.

`HookDocsResultCacheMetaExtension` folded two things into the cache key:

* A hash of every canonical hook docblock reachable through a "This
  filter is documented in <file>" reference, found by scanning
  wp-admin, wp-includes and the bundled themes on every run. Resolving
  a reference now calls `trackFileDependency()` on each candidate path
  it tests, so editing a canonical docblock re-analyzes only the files
  that reference it. A candidate tested before the hit is tracked too,
  since creating it would change which file the reference names.
* A hash of the extension sources in tests/phpstan. PHPStan 2.3 already
  runs a full analysis when the source of any registered extension or
  bootstrap file changes, so this half was redundant.

With both covered, the extension, its whole-tree scan, and the hashing
helpers in `HookDocBlock` are removed.

The rules and the `apply_filters()` return type extension document their
scope as `Scope&DependencyTracker`, which is what PHPStan passes them,
and `HookDocBlock` takes that type in turn.

Verified by adding a `@param` to the canonical `the_title` docblock in
wp-includes/post-template.php with a warm cache: 22 files were
re-analyzed, and every call site inheriting that docblock reported the
parameter count mismatch.

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

github-actions Bot commented Oct 7, 2026

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.

@westonruter
westonruter requested a review from swissspidy October 7, 2026 21:40
@westonruter
westonruter marked this pull request as ready for review October 7, 2026 21:42
@github-actions

github-actions Bot commented Oct 7, 2026

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. You can also manually ask me to refresh this list by adding the props-bot label.

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.

wporg-sync pushed a commit that referenced this pull request Oct 7, 2026
This also updates `phpstan/phpstan-phpunit` to 2.1.1, which requires PHPStan 2.3. The release analyzes code more precisely, so 12 `variable.undefined` baseline entries no longer match. It also reports two comparisons in `WP_HTML_Processor::run_adoption_agency_algorithm()` as constant: every path through the outer loop body returns or calls `bail()`, so the loop never runs a second time. That loop is scaffolding for parts of the algorithm that are not yet supported, so the comparisons are baselined as work still to do.

PHPStan 2.3 deprecates `ResultCacheMetaExtension`, which `HookDocsResultCacheMetaExtension` implemented to discard the whole result cache whenever a hook docblock inherited through a "This filter is documented in" reference changed. Resolving such a reference now declares each candidate file as a dependency of the file being analyzed, so editing a canonical docblock re-analyzes only the files that inherit it, and the scan of the whole tree that ran on every analysis is gone. The extension also hashed the tooling's own sources, which PHPStan 2.3 already does for every registered extension, so it is removed.

Developed in #14089.
Follow-up to r62939, r64012.

Props westonruter, swissspidy.
See #65817.


git-svn-id: https://develop.svn.wordpress.org/trunk@64237 602fd350-edb4-49c9-b593-d223f7449a82
@westonruter westonruter closed this Oct 7, 2026
wporg-sync pushed a commit to WordPress/WordPress that referenced this pull request Oct 7, 2026
This also updates `phpstan/phpstan-phpunit` to 2.1.1, which requires PHPStan 2.3. The release analyzes code more precisely, so 12 `variable.undefined` baseline entries no longer match. It also reports two comparisons in `WP_HTML_Processor::run_adoption_agency_algorithm()` as constant: every path through the outer loop body returns or calls `bail()`, so the loop never runs a second time. That loop is scaffolding for parts of the algorithm that are not yet supported, so the comparisons are baselined as work still to do.

PHPStan 2.3 deprecates `ResultCacheMetaExtension`, which `HookDocsResultCacheMetaExtension` implemented to discard the whole result cache whenever a hook docblock inherited through a "This filter is documented in" reference changed. Resolving such a reference now declares each candidate file as a dependency of the file being analyzed, so editing a canonical docblock re-analyzes only the files that inherit it, and the scan of the whole tree that ran on every analysis is gone. The extension also hashed the tooling's own sources, which PHPStan 2.3 already does for every registered extension, so it is removed.

Developed in WordPress/wordpress-develop#14089.
Follow-up to r62939, r64012.

Props westonruter, swissspidy.
See #65817.

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


git-svn-id: http://core.svn.wordpress.org/trunk@63388 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.

2 participants