Repository navigation
Code Quality: Fix the binaryOp.invalid PHPStan errors and remove the baseline - #15451
mukeshpanchal27 wants to merge 4 commits into
Conversation
`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>
|
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: To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. Props Bot commandsYou can trigger Props Bot actions by commenting on this PR:
|
Test using WordPress PlaygroundThe 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
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
There was a problem hiding this comment.
🟡 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 => trueas required forget_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
| 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; |
`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>

This PR fixes all four
binaryOp.invaliderrors and deletestests/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 throughesc_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 usesabsint()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' => trueand adds 1 to the query result. Theget_page_of_comment_query_argsfilter documentedcountas an optionalbool. After the filter, PHPStan could not tell thatWP_Comment_Query::query()returns an integer.The function cannot work without a count. This PR documents
countastrueand marks itRequired.. The hash notation then makes the key required, and the conditional return type ofWP_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' => trueand+ 1. Since then, a callback that turns offcounthas always crashed this function.On PHP 8.3, each way a filter can turn off
countthrows the same error:counttofalseTypeError: Unsupported operand types: array + intcounttofalse, no older commentsTypeErrorcounttofalsewithfields => idsTypeErrorRemoving the
countkey has the same result, becauseWP_Comment_Querydefaultscounttofalse.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, theuser_idofwp_initialize_site()and thehrefof a preloaded image, because callers can validly leave those keys out. No caller can leave outcounthere 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, whichexplode()returns as a string. Core creates the key astime() . ':' . 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 existingexpired_keyerror. Every key that core creates behaves as before.Testing
composer phpstanreports no errors.php -lpasses on every changed file.trunk.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