Skip to content

Docs: Add PHPStan type assertions - #13896

Open
swissspidy wants to merge 4 commits into
WordPress:trunkfrom
swissspidy:fix/phpstan-assertions-purity
Open

swissspidy wants to merge 4 commits into
WordPress:trunkfrom
swissspidy:fix/phpstan-assertions-purity

Conversation

@swissspidy

@swissspidy swissspidy commented Oct 1, 2026 •

Copy link
Copy Markdown
Member

Split out of #13530, as proposed in this comment (subset 9).

  • @phpstan-assert-if-true is added to wp_is_stream(), wp_is_uuid(), shortcode_exists(), has_shortcode() and taxonomy_exists().

Changes from #13530

These follow the review analysis:

  • wp_is_uuid() asserts =lowercase-string&non-falsy-string without the TUuid of string template, which rejected the mixed its callers pass.

Changes after review

  • The @phpstan-impure annotations are removed for now. Much of WordPress depends on globals and the database, so nearly every function could be marked impure. Core should first agree on which functions to mark, for example only deliberately random ones such as wp_rand() and ones especially likely to change between calls such as get_transient(), as php-stubs does.
  • The @phpstan-pure annotations are removed as well. With the default rememberPossiblyImpureFunctionValues: true, PHPStan already remembers return values, so @phpstan-pure changes nothing (see Remembering and forgetting returned values).
  • path_is_absolute()'s assertion is dropped from this PR, since trunk now has @phpstan-assert-if-true non-falsy-string $path.

Effect on the analysis

composer run phpstan passes with no baseline changes.

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: Splitting #13530 by tag kind, applying the corrections from the review analysis on #13530 and from review on this PR, checking the result with composer run phpstan and drafting the commit messages 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

https://claude.ai/code/session_01T3XYNUvB9sQNDXA14uJQeH

Adds `@phpstan-assert-if-true` to functions that check their argument, such as `taxonomy_exists()`, `shortcode_exists()` and `wp_is_uuid()`, and `@phpstan-pure` and `@phpstan-impure` to functions whose result depends only on their arguments, or does not.

`addslashes_gpc()` is not marked as pure, since it calls `_deprecated_function()`.

See #65817.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VieGtSQtUoVfHiGwTmkvtc
Copilot AI balanced review requested due to automatic review settings October 1, 2026 09:02
@github-actions

github-actions Bot commented Oct 1, 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 swissspidy, marian1.

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

@github-actions

github-actions Bot commented Oct 1, 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.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The annotations accurately reflect the reviewed function behavior and introduce no runtime changes.

Review effort: Balanced
Findings: None

What changed in this PR

Adds PHPStan annotations to improve type narrowing and correctly model deterministic and state-dependent functions, without runtime changes.

Changes:

  • Adds conditional type assertions to validation helpers.
  • Marks deterministic helpers as pure.
  • Marks random, time-dependent, and stateful functions as impure.
File Description
src/​wp-includes/​user.php Marks password reset key generation impure.
src/​wp-includes/​taxonomy.php Adds taxonomy-name type assertion.
src/​wp-includes/​shortcodes.php Adds shortcode assertions and purity metadata.
src/​wp-includes/​rest-api.php Marks boolean sanitization pure.
src/​wp-includes/​pluggable.php Marks mail, nonce, password, and random functions impure.
src/​wp-includes/​option.php Marks transient retrieval impure.
src/​wp-includes/​functions.php Adds assertions and purity metadata to general helpers.
src/​wp-includes/​formatting.php Marks deterministic formatting helpers pure.
src/​wp-admin/​includes/​menu.php Marks CSS-class composition pure.
src/​wp-admin/​includes/​bookmark.php Marks request-dependent link defaults impure.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Copy link
Copy Markdown
Member Author

🤖 Comment by Claude Opus 5.5

Props for this subset, gathered from the full history of functionMap.php in php-stubs/wordpress-stubs. A change counts only where it introduced or changed the specific tag this PR carries, not just any change to the function's map entry. Purely mechanical changes are left out: tag key renames (php-stubs/wordpress-stubs#420), parameter renames (php-stubs/wordpress-stubs#115), coding standards (php-stubs/wordpress-stubs#119) and the duplicate-code refactor (php-stubs/wordpress-stubs#85).

Stubs change Author Entries
php-stubs/wordpress-stubs#328 @IanDelMar wp_is_uuid()
php-stubs/wordpress-stubs#336 @IanDelMar wp_generate_uuid4()
php-stubs/wordpress-stubs#337 @IanDelMar wp_rand()
php-stubs/wordpress-stubs#338 @IanDelMar get_password_reset_key()
php-stubs/wordpress-stubs#339 @IanDelMar wp_generate_password()
php-stubs/wordpress-stubs#348 @IanDelMar wp_nonce_tick()
php-stubs/wordpress-stubs#352 @IanDelMar taxonomy_exists()
php-stubs/wordpress-stubs#354 @IanDelMar wp_unique_id(), wp_unique_prefixed_id()
php-stubs/wordpress-stubs#359 @IanDelMar get_default_link_to_edit()
php-stubs/wordpress-stubs#361 @IanDelMar has_shortcode()
php-stubs/wordpress-stubs#365 @IanDelMar bool_from_yn()
php-stubs/wordpress-stubs#369 @IanDelMar wp_slash()
php-stubs/wordpress-stubs#371 @IanDelMar wp_is_numeric_array()
php-stubs/wordpress-stubs#374 @IanDelMar get_shortcode_atts_regex()
php-stubs/wordpress-stubs#385 @IanDelMar shortcode_exists()
php-stubs/wordpress-stubs#387 @IanDelMar rest_sanitize_boolean()
php-stubs/wordpress-stubs#388 @IanDelMar trailingslashit()
php-stubs/wordpress-stubs#390 @IanDelMar backslashit(), untrailingslashit()
php-stubs/wordpress-stubs#461 @PeterSmith8nss get_transient(), wp_mail()
php-stubs/wordpress-stubs#482 @IanDelMar and @szepeviktor path_is_absolute()
php-stubs/wordpress-stubs#484 @IanDelMar add_cssclass()
php-stubs/wordpress-stubs#489 @IanDelMar wp_is_stream()

I couldn't find a WordPress.org profile for @PeterSmith8nss. That GitHub login is listed as a placeholder until the username is confirmed.

Props for this PR (swissspidy for the split, westonruter for the review that shaped it):

swissspidy, westonruter, marian1, szepeviktor, PeterSmith8nss

Generated by Claude Code

@IanDelMar

Copy link
Copy Markdown
  • @phpstan-impure is added to functions whose result changes between calls, even with the same arguments.

@phpstan-impure could be added to almost all WordPress functions, as WordPress relies heavily on globals and database queries. In php-stubs, we decided to mark only functions that are deliberately random (e.g., wp_rand()) or particularly likely to return different values across calls (e.g., get_transient()) as impure. I think this could be a good approach for core as well.

Anyone who does not want PHPStan to remember potentially impure return values can set rememberPossiblyImpureFunctionValues: false (see the PHPStan configuration reference). In that case, @phpstan-pure becomes more relevant. While rememberPossiblyImpureFunctionValues is set to true (default behaviour), @phpstan-pure does not affect whether PHPStan remembers a function's return value.

It would be a good idea to agree on an approach before adding @phpstan-impure throughout core.

swissspidy and others added 3 commits October 5, 2026 15:41
…ns-purity

# Conflicts:
#	src/wp-includes/formatting.php
#	src/wp-includes/functions.php
#	src/wp-includes/shortcodes.php
Drop `@phpstan-impure` until there is agreement on which functions core should mark as impure, given how much of WordPress depends on globals and the database. Drop `@phpstan-pure` too, since with the default `rememberPossiblyImpureFunctionValues: true` it does not change whether PHPStan remembers a function's return value.

See #65817.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T3XYNUvB9sQNDXA14uJQeH
@swissspidy swissspidy changed the title Docs: Add PHPStan type assertions and purity annotations Docs: Add PHPStan type assertions Oct 8, 2026
@swissspidy
swissspidy requested a review from westonruter October 8, 2026 07:47
@IanDelMar

Copy link
Copy Markdown

I do not understand the decision to remove the @phpstan-pure annotations again. They are valuable for anyone analysing code with rememberPossiblyImpureFunctionValues set to false - potentially including core itself at some point. They also provide useful information for WordPress core developers.

@swissspidy

swissspidy commented Oct 8, 2026 •

Copy link
Copy Markdown
Member Author

I wanna add those in a separate PR

Edit: see below.

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.

3 participants