Skip to content

Build/QA: Retire parameterByRef.unusedType baseline - #14025

Open
huzaifaalmesbah wants to merge 3 commits into
WordPress:trunkfrom
huzaifaalmesbah:phpstan/retire-parameter-by-ref-unused-type
Open

huzaifaalmesbah wants to merge 3 commits into
WordPress:trunkfrom
huzaifaalmesbah:phpstan/retire-parameter-by-ref-unused-type

Conversation

@huzaifaalmesbah

@huzaifaalmesbah huzaifaalmesbah commented Oct 6, 2026 •

Copy link
Copy Markdown
Member

Description

In src/wp-includes/compat-utf8.php, by-reference parameters in _wp_scan_utf8() (&$has_noncharacters) and _wp_utf8_codepoint_span() (&$found_code_points) accept nullable input defaults, but are always assigned non-null values on exit (bool and int respectively).

Additionally, in _wp_scan_utf8(), $has_noncharacters was previously accumulated using bitwise OR assignment (|=), which coerced the boolean variable into an integer (0 or 1). Switching to boolean accumulating assignment ($has_noncharacters = $has_noncharacters || ( ... )) ensures it remains strictly a boolean.

This PR:

  1. Adds @param-out bool $has_noncharacters to _wp_scan_utf8().
  2. Adds @param-out int $found_code_points to _wp_utf8_codepoint_span(). The existing @param lines are unchanged; the developer reference only renders tags named param, so the published docs pages are unaffected.
  3. Retires and deletes tests/phpstan/baselines/parameterByRef.unusedType.neon and updates phpstan.neon.dist.
  4. Decrements 2 errors in tests/phpstan/baselines/parameterByRef.type.neon.
  5. Adds unit tests covering _wp_scan_utf8(): code point counts for two-, three- and four-byte sequences, combining characters, ZWJ sequences and grapheme clusters (verified against mb_strlen()), maximal subparts of invalid byte spans, and boolean noncharacter detection.

Testing Instructions

  1. Run composer phpstan locally to confirm analysis passes with 0 errors.
  2. Run unit tests for charset compat functions:
    npm run test:php -- --filter=Tests_Compat_wpScanUtf8
    npm run test:php -- --filter=Tests_Compat_wpScanUtf8 -c tests/phpunit/multisite.xml
    npm run test:php -- --filter=Tests_Compat_wpUtf8CodePointSpan
  3. Run PHPCS to verify coding standards:
    vendor/bin/phpcs src/wp-includes/compat-utf8.php tests/phpunit/tests/compat/wpScanUtf8.php

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

Use of AI Tools

AI assistance: Yes
Tool(s): Google Antigravity, Claude Code
Model(s): Gemini 3.8 Flash, Claude Opus 5.5
Used for: Assisting with static analysis archaeology, PHPStan baseline synchronization, and diff preparation; all code and tests were manually reviewed, verified, and locally run by me.

@github-actions

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

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

Props huzaifaalmesbah, dmsnell, lancewillett.

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 or WordPress.org 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.

@github-actions

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

🟢 Approval recommended

There are no active review issues for the UTF-8 output-type clarifications and related PHPStan suppression cleanup.

No open issues 🎉

What changed in this PR

This PR clarifies by-reference output types in WordPress’s UTF-8 compatibility helpers and removes the PHPStan suppressions those changes resolve.

Changes:

  • Adds output-type annotations and keeps noncharacter detection strictly boolean.
  • Deletes the parameterByRef.unusedType baseline and removes two resolved parameterByRef.type errors.
  • Adds UTF-8 scanner tests covering ASCII, noncharacters, and ordinary multibyte text.
File Description
tests/​phpunit/​tests/​compat/​wpScanUtf8.php Adds scanner tests asserting boolean noncharacter results.
tests/​phpstan/​baselines/​parameterByRef.unusedType.neon Deletes the resolved baseline.
tests/​phpstan/​baselines/​parameterByRef.type.neon Removes two resolved boolean-type suppressions.
src/​wp-includes/​compat-utf8.php Documents output types and replaces bitwise accumulation with boolean logic.
phpstan.neon.dist Removes the deleted baseline’s include.

Review effort: Balanced

@lancewillett
lancewillett requested a review from dmsnell October 31, 2026 19:59
@lancewillett

Copy link
Copy Markdown
Member

@dmsnell could you review the _wp_scan_utf8() changes and associated coverage? This adjusts executable boolean accumulation as well as PHPStan annotations, so I am holding landing for your review. Optional test cleanup: assertTrue() and assertFalse() already check the boolean type, making the preceding assertIsBool() assertions redundant.

AI review · gpt-6

…sts.

`assertTrue()` and `assertFalse()` already check the boolean type.
@lancewillett

Copy link
Copy Markdown
Member

@dmsnell following up on my Oct 31 request: could you review the _wp_scan_utf8() changes and their coverage when you have time?

AI review · claude-opus-5-5

* @param int|null $max_bytes Stop scanning after this many bytes have been seen.
* @param int|null $max_code_points Stop scanning after this many code points have been seen.
* @param bool|null $has_noncharacters Set to indicate if scanned string contained noncharacters.
* @param-out bool $has_noncharacters

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

please verify that this doesn’t break the docs-generation. before we start changing @param declarations, we should ensure that the published docs page isn’t broken.

you can hopefully lean on dmsnell#29 to figure out how to preview the generation.

I see that this is an additional annotation beyond the @param, but it would be ideal to double-check first.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Thanks for flagging this. I couldn't build the full Playground preview locally, so I checked the parser and theme versions pinned in your preview branch instead. The docblock tag regex allows -, so @param-out comes through as its own param-out tag rather than a @param. The reference templates only read tags named param for the signature and the Parameters section, so the published page should stay the same. I also reverted the @param wording change on _wp_utf8_codepoint_span() in 9b682d6, so now the docblock only gains the @param-out lines.

*
* @ticket 65817
*/
public function test_scan_string_without_noncharacters() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this is a misleading title. it would be clearer to show variant cases of multi-byte UTF-8 code points and extended grapheme clusters, which would clarify the behavior of the function.

let’s use a data provider and show interesting cases, and then use mb_strlen( $text, 'UTF-8' ) inside an assertSame() to verify the counts.

this way we can cover two-, three-, and four-byte sequences, spans of invalid bytes (covering the maximal subpart behavior), ZWJ sequences, and grapheme clusters.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good call, thank you. Done in 9b682d6. data_valid_utf8() now covers two-, three- and four-byte sequences, combining marks, conjoining jamo, flags, skin tone and keycap sequences, and ZWJ sequences, with the count checked against mb_strlen( $text, 'UTF-8' ). Invalid spans have their own provider, which walks the string and checks the maximal subpart length of each span. The expected values are written out in the data there, so they don't depend on how mbstring handles invalid bytes.

Replaces the ASCII and "without noncharacters" tests with data providers
covering two-, three- and four-byte sequences, combining characters,
ZWJ sequences and grapheme clusters, with the code point count verified
against `mb_strlen()`. Adds cases for invalid byte spans that check the
maximal subpart reported for each one.

Also restores the original `@param` line for `$found_code_points` in
`_wp_utf8_codepoint_span()`, so the only docblock additions are the
`@param-out` tags, which the developer reference does not render.

See #65817.
// Covers the range U+FDD0–U+FDEF, U+FFFE, U+FFFF.
if ( 0xEF === $b1 ) {
$has_noncharacters |= (
$has_noncharacters = $has_noncharacters || (

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this might result in a performance degradation inside a hot path, but I have not measured the change. it takes a branchless instruction and replaces it with a branching one.

in any case, this compat function is mostly here for edge cases where the built-in UTF-8 support is lacking, so if it does introduce a performance regression, that may be tolerable if the ultimate goal is ensuring that nothing expected appears for the types.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Thanks, good point. I ran a quick benchmark to check. I compared the original |=, the || in this PR, and a third option that keeps a branchless |= on a local int and casts to bool before each return. Each ran on about 1 MB of text, 15 runs, taking the median, two separate runs each:

Text PHP 8.5 (native) PHP 8.3 (Docker)
all 4-byte emoji +0.3% / +3.0% +0.1% / −3.4%
all fullwidth 0xEF +1.3% / −2.1% +2.8% / +0.3%
CJK, 3-byte without 0xEF −1.1% / +0.3% +6.7% / +2.9%
mostly Latin with some emoji +1.0% / +1.1% −0.2% / −3.2%

These are || vs |=. The differences change direction between runs, and the largest one is on CJK text, where the changed line never runs, so it looks like noise rather than a regression. The local cast version wasn't consistently faster either. I'd lean toward keeping || for simplicity, but I'm happy to switch to the local cast version if you prefer to keep the hot path branchless.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In review

Development

Successfully merging this pull request may close these issues.

4 participants