Skip to content

Code Quality: Fix the binaryOp.invalid PHPStan errors and remove the baseline - #15451

Open
mukeshpanchal27 wants to merge 4 commits into
WordPress:trunkfrom
mukeshpanchal27:fix/binaryop-invalid-baseline
Open

mukeshpanchal27 wants to merge 4 commits into
WordPress:trunkfrom
mukeshpanchal27:fix/binaryop-invalid-baseline

Conversation

@mukeshpanchal27

Copy link
Copy Markdown
Member

This PR fixes all four binaryOp.invalid errors and deletes tests/phpstan/baselines/binaryOp.invalid.neon. Each file has its own commit.

None of the four errors is a false positive. Each one is arithmetic on a value whose type does not guarantee a number.

Twenty Twenty: custom logo dimensions (2 errors)

twentytwenty_get_custom_logo() passed the logo width and height through esc_attr(), then divided them by 2 for retina logos. esc_attr() returns a string. wp_get_attachment_image_src() returns integer dimensions, so this PR uses absint() instead. It keeps the values as integers and still sanitizes a filtered value. The generated HTML is unchanged for every valid dimension.

get_page_of_comment(): comment count (1 error)

The function sets 'count' => true and adds 1 to the query result. The get_page_of_comment_query_args filter documented count as an optional bool. After the filter, PHPStan could not tell that WP_Comment_Query::query() returns an integer.

The function cannot work without a count. This PR documents count as true and marks it Required.. The hash notation then makes the key required, and the conditional return type of WP_Comment_Query::query() resolves to an integer. There is no runtime change.

Backward compatibility

This change only narrows the documented filter contract. It does not break any working callback:

  • The filter was added in 5.5.0 (r48133), between the existing 'count' => true and + 1. Since then, a callback that turns off count has always crashed this function.

  • On PHP 8.3, each way a filter can turn off count throws the same error:

    What the filter does Query result Outcome
    Sets count to false List of comments TypeError: Unsupported operand types: array + int
    Sets count to false, no older comments Empty array Same TypeError
    Sets count to false with fields => ids List of IDs Same TypeError

    Removing the count key has the same result, because WP_Comment_Query defaults count to false.

  • Core fires this filter in one place only, so the Required. key cannot cause errors at another call site.

  • r65217 added the Required. marker and removed two wrong ones, the user_id of wp_initialize_site() and the href of a preloaded image, because callers can validly leave those keys out. No caller can leave out count here without a fatal error.

check_password_reset_key(): request time (1 error)

The function splits the stored key on : and adds the expiration duration to the first part, which explode() returns as a string. Core creates the key as time() . ':' . wp_fast_hash( $key ), so this PR casts the first part to an integer.

This is the only change with a runtime effect, and only for a corrupted key with a non-numeric prefix. On PHP 8 that case used to throw a TypeError. It now gives an expiration time in the past, so the function returns its existing expired_key error. Every key that core creates behaves as before.

Testing

  • composer phpstan reports no errors.
  • php -l passes on every changed file.
  • PHPCS reports the same warnings on the changed files as on trunk.
  • I could not run PHPUnit locally, because no test database is available. CI will run the related tests.

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: Finding the cause of each error, editing the code and baseline, and drafting the PR. I reviewed the changes.


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

mukeshpanchal27 and others added 3 commits November 4, 2026 14:58
`twentytwenty_get_custom_logo()` passed the logo width and height through `esc_attr()`, then divided them by 2 for retina logos. `esc_attr()` returns a string, so PHPStan reported `binaryOp.invalid` for each division. `wp_get_attachment_image_src()` returns integer dimensions, so `absint()` keeps them as integers and still sanitizes a filtered value. The generated HTML is unchanged for every valid dimension.

This change removes the matching `binaryOp.invalid` baseline entry.

See #65817.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…` filter.

`get_page_of_comment()` sets `'count' => true` and adds 1 to the result of the comment query to calculate the page number. The filter documented `count` as an optional `bool`. PHPStan therefore could not tell that `WP_Comment_Query::query()` returns an integer here, and reported `binaryOp.invalid` for the addition. If a filter set `count` to `false`, the addition would throw a `TypeError`.

This change documents `count` as `true` and marks it `Required.`, so the conditional return type of `WP_Comment_Query::query()` resolves to an integer. It also removes the matching `binaryOp.invalid` baseline entry. There is no runtime change.

See #65817.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`check_password_reset_key()` splits the stored activation key on `:` and adds the expiration duration to the first part. `explode()` returns strings, so PHPStan reported `binaryOp.invalid` for the addition. Core creates the key as `time() . ':' . wp_fast_hash( $key )`, so the first part is a Unix timestamp. This change casts it to an integer before the addition.

The result is the same for every key that core creates. For a corrupted key with a non-numeric prefix, the addition used to throw a `TypeError` on PHP 8. It now gives an expiration time in the past, so the function returns its existing `expired_key` error.

This change also deletes the now empty `binaryOp.invalid` baseline and removes its `includes` line from `phpstan.neon.dist`.

See #65817.

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

github-actions Bot commented Nov 4, 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 mukesh27.

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.

@github-actions

github-actions Bot commented Nov 4, 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.

🟡 Changes recommended

An active issue remains because the malformed non-numeric timestamp case lacks a regression test confirming it returns the expected expired_key result.

1 open issue
What changed in this PR

This PR resolves the four binaryOp.invalid PHPStan errors by preserving numeric types, tightening the comment-query contract, and removing the obsolete baseline configuration.

Changes:

  • Casts password-reset timestamps to integers before arithmetic.
  • Uses absint() for Twenty Twenty custom-logo dimensions.
  • Documents count => true as required for get_page_of_comment().
  • Removes the obsolete PHPStan baseline and configuration include.
  • Nit: Add PHPUnit coverage for malformed password-reset timestamps with a non-numeric prefix.
File Description
tests/​phpstan/​baselines/​binaryOp.invalid.neon Deletes the obsolete PHPStan baseline.
src/​wp-includes/​user.php Casts the password-reset timestamp prefix before calculating expiration.
src/​wp-includes/​comment.php Documents the comment query’s required count => true contract.
src/​wp-content/​themes/​twentytwenty/​functions.php Keeps custom-logo dimensions numeric during retina calculations.
phpstan.neon.dist Removes the deleted baseline include.

Review effort: Lite

Comment thread src/wp-includes/user.php
if ( str_contains( $user->user_activation_key, ':' ) ) {
list( $pass_request_time, $pass_key ) = explode( ':', $user->user_activation_key, 2 );
$expiration_time = $pass_request_time + $expiration_duration;
$expiration_time = (int) $pass_request_time + $expiration_duration;

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.

Addressed in 21b3316

`check_password_reset_key()` now casts the timestamp part of a stored key to an integer. For a key with a valid hash and a non-numeric timestamp, the function returns the `expired_key` error. Before the cast, the same key threw a `TypeError` on PHP 8. This test covers that case, so the error cannot come back unnoticed.

See #65817.

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

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

No active review issues remain for the PHPStan arithmetic fixes and related baseline cleanup.

1 open issue

Review effort: Balanced

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