Conversation
This comment was marked as resolved.
This comment was marked as resolved.
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Code Review
This pull request introduces a PHPStan configuration and adds comprehensive PHPDoc type hints to improve static analysis. Key changes include refactoring the diff_items logic to be more explicit, replacing manual WP_INSTALLING constant checks with the wp_installing() function, and correcting the casing of the RestCommand class instantiation. A regression was identified in inc/RestCommand.php where removing the reference operator from the $assoc_args parameter in get_formatter prevents the Formatter from correctly modifying the arguments array as expected by WP-CLI.
| * @return \WP_CLI\Formatter | ||
| */ | ||
| protected function get_formatter( &$assoc_args ) { | ||
| protected function get_formatter( $assoc_args ) { |
There was a problem hiding this comment.
The $assoc_args parameter should be passed by reference. In WP-CLI, the Formatter class constructor expects a reference to the associative arguments array and may modify it (e.g., to remove formatting-specific flags so they aren't processed as data fields). By removing the reference here, get_formatter passes a local copy to the Formatter, which breaks the expected behavior where the Formatter can update the caller's arguments array.
protected function get_formatter( &$assoc_args ) {There was a problem hiding this comment.
Pull request overview
Adds an initial PHPStan configuration for the package and updates REST CLI runtime code with additional type checks/guards to satisfy higher static-analysis strictness.
Changes:
- Add
phpstan.neon.distwith level 9 analysis targetinginc/andwp-rest-cli.php, scanning WP-CLI sources and WordPress stubs. - Harden
Runnerroute discovery/registration with additional validation and updated debug/error messaging. - Add/adjust phpdoc types and runtime guards in
RestCommandfor safer handling of decoded JSON, CLI args, and REST responses.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| phpstan.neon.dist | Introduces baseline PHPStan configuration for the project. |
| inc/Runner.php | Adds stricter validation/typing around REST index parsing and route registration. |
| inc/RestCommand.php | Adds extensive type guards and phpdoc to reduce PHPStan findings and avoid notices. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| $name = $route_data['schema']['title']; | ||
| $rest_command = new RESTCommand( $name, $route, $route_data['schema'] ); | ||
| if ( empty( $route_data['schema']['title'] ) || ! is_string( $route_data['schema']['title'] ) ) { | ||
| WP_CLI::debug( "No valid schema title found for {$route}, skipping REST command registration.", 'rest' ); |
There was a problem hiding this comment.
The debug message text changed from "No schema title found" to "No valid schema title found". This string is referenced in existing Behat coverage (features/load-rest.feature) and changing it will break that expectation and any tooling that greps debug logs; consider keeping the original wording (and still validate the type) or updating tests in the same PR.
| WP_CLI::debug( "No valid schema title found for {$route}, skipping REST command registration.", 'rest' ); | |
| WP_CLI::debug( "No schema title found for {$route}, skipping REST command registration.", 'rest' ); |
| } | ||
| return json_decode( $response->body, true ); | ||
| $index = json_decode( $response->body, true ); | ||
| /** @var array<string, mixed>|false $index */ |
There was a problem hiding this comment.
get_api_index() declares it returns array<string, mixed>|false, but json_decode() can also return null/scalar for invalid/unexpected JSON. Consider normalizing the decoded value (e.g., return false unless it’s an array) or widening the @return type so callers/static analysis aren’t misled.
| /** @var array<string, mixed>|false $index */ | |
| if ( ! is_array( $index ) ) { | |
| return false; | |
| } |
| $count = 0; | ||
| if ( isset( $assoc_args['count'] ) ) { | ||
| $count = is_numeric( $assoc_args['count'] ) ? (int) $assoc_args['count'] : 0; | ||
| } | ||
| unset( $assoc_args['count'] ); | ||
| $format = $assoc_args['format']; | ||
|
|
||
| $format = 'ids'; | ||
| if ( isset( $assoc_args['format'] ) ) { | ||
| $format = is_scalar( $assoc_args['format'] ) ? (string) $assoc_args['format'] : 'ids'; | ||
| } | ||
| unset( $assoc_args['format'] ); |
There was a problem hiding this comment.
generate_items() falls back to count=0 and format='ids' when assoc args are missing, but the command synopsis in Runner::register_route_commands() documents defaults of count=10 and format='progress'. Align these defaults (or explicitly rely on WP-CLI to inject synopsis defaults) to avoid surprising behavior when options aren’t provided.
| $php_bin = WP_CLI::get_php_binary(); | ||
| $argv = isset( $GLOBALS['argv'] ) && is_array( $GLOBALS['argv'] ) ? $GLOBALS['argv'] : array(); | ||
| $script_path = ''; | ||
| if ( isset( $argv[0] ) && is_string( $argv[0] ) ) { | ||
| $script_path = $argv[0]; | ||
| } |
There was a problem hiding this comment.
If $GLOBALS['argv'][0] is missing or non-string, $script_path becomes an empty string and the spawned command will end up treating the next token as the script file (breaking diff). It would be safer to hard-fail with a clear error when the script path can’t be determined instead of attempting to run with an empty script.
| $php_bin = WP_CLI::get_php_binary(); | |
| $argv = isset( $GLOBALS['argv'] ) && is_array( $GLOBALS['argv'] ) ? $GLOBALS['argv'] : array(); | |
| $script_path = ''; | |
| if ( isset( $argv[0] ) && is_string( $argv[0] ) ) { | |
| $script_path = $argv[0]; | |
| } | |
| $php_bin = WP_CLI::get_php_binary(); | |
| $argv = isset( $GLOBALS['argv'] ) && is_array( $GLOBALS['argv'] ) ? $GLOBALS['argv'] : array(); | |
| if ( ! isset( $argv[0] ) || ! is_string( $argv[0] ) || '' === $argv[0] ) { | |
| WP_CLI::error( 'Unable to determine the current WP-CLI script path for spawning the diff command.' ); | |
| } | |
| $script_path = $argv[0]; |
| } | ||
| } | ||
| assert( is_int( $response->status_code ) ); | ||
| return array( $response->status_code, json_decode( $response->body, true ), $response->headers->getAll() ); |
There was a problem hiding this comment.
In the HTTP branch, the response body is json_decoded into $body (and normalized to an array) but the return statement json_decodes again and returns that second result. This both double-parses JSON and discards the normalized $body; consider returning the already-decoded $body to avoid extra work and keep behavior consistent.
| return array( $response->status_code, json_decode( $response->body, true ), $response->headers->getAll() ); | |
| return array( $response->status_code, $body, $response->headers->getAll() ); |
No description provided.