Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
2d0d64d
PHPStan level 7
swissspidy May 14, 2025
9347dbe
PHPStan level 8
swissspidy May 16, 2025
bc0dc68
Lint fixes
swissspidy May 16, 2025
79fcf5f
Update PHPCS config
swissspidy May 16, 2025
2519f5d
Move comment
swissspidy May 16, 2025
39e4662
Tackle some mixed types
swissspidy May 17, 2025
e2253cd
Tackle some mixed types
swissspidy May 17, 2025
af0c3ea
PHPStan level 9
swissspidy May 17, 2025
8c64fcb
Fix some tests too
swissspidy May 17, 2025
7b3c569
Fix pass by ref
swissspidy May 17, 2025
9ea8376
Merge branch 'add/bump-requirements' into try/phpstan
swissspidy May 17, 2025
0d0a636
Remove some more old compat code
swissspidy May 18, 2025
a839504
Declare dynamic Formatter properties
swissspidy May 18, 2025
4c3a1ad
Make fetchers generic
swissspidy May 18, 2025
6d20af8
Annotate `NoOp` class
swissspidy May 19, 2025
0ac1ac3
Use iterable
swissspidy May 19, 2025
ff2ba36
Make `get_upgrader` generic
swissspidy May 20, 2025
d870bea
Fix vars
swissspidy May 20, 2025
990aaa8
Types for `get_config`()/`has_config()`
swissspidy May 21, 2025
12ea230
Tweak `WpOrgApi`
swissspidy May 21, 2025
c1f77d4
Allow int in `get_flag_value`
swissspidy May 21, 2025
60bbc35
Improve type for `iterator_map`
swissspidy May 21, 2025
7c1d378
Leverage latest wp-cli-tests updates
swissspidy May 22, 2025
3e080da
Enable some strict rules
swissspidy May 22, 2025
3cfe02c
Composer update
swissspidy May 23, 2025
6da28c0
Merge branch 'main' into try/phpstan
swissspidy Jun 11, 2025
baf694a
Support numeric-indexed arrays
swissspidy Jun 12, 2025
75f2379
mock builder fix
swissspidy Jun 12, 2025
8693aa0
Add attributes for data providers
swissspidy Jun 12, 2025
859e549
Fix wpdb mock
swissspidy Jun 18, 2025
eea0170
Add some missing attributes
swissspidy Jun 18, 2025
0695877
ignore error
swissspidy Jun 18, 2025
444b150
Apply suggestion from code review
swissspidy Jun 21, 2025
a25c30c
Ignore error inline
swissspidy Jun 23, 2025
91371ad
Add return types to tests
swissspidy Jun 23, 2025
d0b0fa5
Add `void` return type to private methods
swissspidy Jun 23, 2025
77bddd2
Merge branch 'main' into try/phpstan
swissspidy Jul 1, 2025
20441a1
Update `wp_get_table_names` type
swissspidy Jul 1, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"wp-cli/entity-command": "^1.2 || ^2",
"wp-cli/extension-command": "^1.1 || ^2",
"wp-cli/package-command": "^1 || ^2",
"wp-cli/wp-cli-tests": "^4.3.10"
"wp-cli/wp-cli-tests": "dev-add/phpstan-enhancements"
},
"suggest": {
"ext-readline": "Include for a better --prompt implementation",
Expand All @@ -30,7 +30,8 @@
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true,
"johnpbloch/wordpress-core-installer": true
"johnpbloch/wordpress-core-installer": true,
"phpstan/extension-installer": true
},
"process-timeout": 7200,
"sort-packages": true,
Expand Down Expand Up @@ -62,11 +63,13 @@
"lint": "run-linter-tests",
"phpcs": "run-phpcs-tests",
"phpcbf": "run-phpcbf-cleanup",
"phpstan": "run-phpstan-tests",
"phpunit": "run-php-unit-tests",
"prepare-tests": "install-package-tests",
"test": [
"@lint",
"@phpcs",
"@phpstan",
"@phpunit",
"@behat"
]
Expand Down
11 changes: 10 additions & 1 deletion php/WP_CLI/Bootstrap/AutoloaderStep.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,16 @@
return false;
}

$composer = json_decode( file_get_contents( $maybe_composer_json ) );
$contents = file_get_contents( $maybe_composer_json );

if ( false === $contents ) {
return false;

Check warning on line 84 in php/WP_CLI/Bootstrap/AutoloaderStep.php

View check run for this annotation

Codecov / codecov/patch

php/WP_CLI/Bootstrap/AutoloaderStep.php#L84

Added line #L84 was not covered by tests
}

/**
* @var object{config: object{'vendor-dir': string}} $composer
*/
$composer = json_decode( $contents );

if ( ! empty( $composer->config )
&& ! empty( $composer->config->{'vendor-dir'} )
Expand Down
6 changes: 6 additions & 0 deletions php/WP_CLI/Bootstrap/CheckRoot.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ class CheckRoot implements BootstrapStep {
* @return BootstrapState Modified state to pass to the next step.
*/
public function process( BootstrapState $state ) {
/**
* @var array{'allow-root'?: bool} $config
*/
$config = $state->getValue( 'config', [] );
if ( array_key_exists( 'allow-root', $config ) && true === $config['allow-root'] ) {
// They're aware of the risks and set a flag to allow root.
Expand All @@ -33,6 +36,9 @@ public function process( BootstrapState $state ) {
return $state;
}

/**
* @var string[] $args
*/
$args = $state->getValue( 'arguments', [] );
if ( count( $args ) >= 2 && 'cli' === $args[0] && in_array( $args[1], [ 'update', 'info' ], true ) ) {
// Make it easier to update root-owned copies.
Expand Down
6 changes: 3 additions & 3 deletions php/WP_CLI/Bootstrap/DefineProtectedCommands.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@
/**
* Get the list of protected commands.
*
* @return array
* @return string[]
*/
private function get_protected_commands() {
private function get_protected_commands(): array {

Check warning on line 40 in php/WP_CLI/Bootstrap/DefineProtectedCommands.php

View check run for this annotation

Codecov / codecov/patch

php/WP_CLI/Bootstrap/DefineProtectedCommands.php#L40

Added line #L40 was not covered by tests
return [
'cli info',
'package',
Expand All @@ -49,7 +49,7 @@
*
* @return string Current command to be executed.
*/
private function get_current_command() {
private function get_current_command(): string {

Check warning on line 52 in php/WP_CLI/Bootstrap/DefineProtectedCommands.php

View check run for this annotation

Codecov / codecov/patch

php/WP_CLI/Bootstrap/DefineProtectedCommands.php#L52

Added line #L52 was not covered by tests
$runner = new RunnerInstance();

return implode( ' ', (array) $runner()->arguments );
Expand Down
3 changes: 2 additions & 1 deletion php/WP_CLI/Bootstrap/IncludeRequestsAutoloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
}

if ( class_exists( '\\Requests' ) ) {
// @phpstan-ignore staticMethod.deprecated, staticMethod.deprecatedClass
\Requests::register_autoloader();
$this->store_requests_meta( RequestsLibrary::CLASS_NAME_V1, self::FROM_WP_CORE );
return $state;
Expand Down Expand Up @@ -124,7 +125,7 @@
* @param string $class_name The class name of the Requests integration.
* @param string $source The source of the Requests integration.
*/
private function store_requests_meta( $class_name, $source ) {
private function store_requests_meta( $class_name, $source ): void {

Check warning on line 128 in php/WP_CLI/Bootstrap/IncludeRequestsAutoloader.php

View check run for this annotation

Codecov / codecov/patch

php/WP_CLI/Bootstrap/IncludeRequestsAutoloader.php#L128

Added line #L128 was not covered by tests
RequestsLibrary::set_version(
RequestsLibrary::CLASS_NAME_V2 === $class_name
? RequestsLibrary::VERSION_V2
Expand Down
3 changes: 3 additions & 0 deletions php/WP_CLI/Bootstrap/InitializeContexts.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ public function process( BootstrapState $state ) {
Context::AUTO => new Context\Auto( $context_manager ),
];

/**
* @var array<string, Context> $contexts
*/
$contexts = WP_CLI::do_hook( 'before_registering_contexts', $contexts );

foreach ( $contexts as $name => $implementation ) {
Expand Down
2 changes: 1 addition & 1 deletion php/WP_CLI/Bootstrap/InitializeLogger.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
/**
* Load the class declarations for the loggers.
*/
private function declare_loggers() {
private function declare_loggers(): void {

Check warning on line 34 in php/WP_CLI/Bootstrap/InitializeLogger.php

View check run for this annotation

Codecov / codecov/patch

php/WP_CLI/Bootstrap/InitializeLogger.php#L34

Added line #L34 was not covered by tests
$logger_dir = WP_CLI_ROOT . '/php/WP_CLI/Loggers';
$iterator = new DirectoryIterator( $logger_dir );

Expand Down
9 changes: 6 additions & 3 deletions php/WP_CLI/Bootstrap/LaunchRunner.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@ final class LaunchRunner implements BootstrapStep {
public function process( BootstrapState $state ) {
$runner = new RunnerInstance();

$runner()->register_context_manager(
$state->getValue( 'context_manager' )
);
/**
* @var \WP_CLI\ContextManager $context_manager
*/
$context_manager = $state->getValue( 'context_manager' );

$runner()->register_context_manager( $context_manager );

$runner()->start();

Expand Down
4 changes: 2 additions & 2 deletions php/WP_CLI/Bootstrap/LoadRequiredCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ public function process( BootstrapState $state ) {
if ( in_array( $path, $required_files[ $scope ], true ) ) {
switch ( $scope ) {
case 'global':
$context = ' (from global ' . Utils\basename( $runner()->get_global_config_path() ) . ')';
$context = ' (from global ' . Utils\basename( (string) $runner()->get_global_config_path() ) . ')';
break;
case 'project':
$context = ' (from project\'s ' . Utils\basename( $runner()->get_project_config_path() ) . ')';
$context = ' (from project\'s ' . Utils\basename( (string) $runner()->get_project_config_path() ) . ')';
break;
case 'runtime':
$context = ' (from runtime argument)';
Expand Down
6 changes: 2 additions & 4 deletions php/WP_CLI/Completions.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public function __construct( $line ) {
array_shift( $this->words );

// Last word is either empty or an incomplete subcommand.
$this->cur_word = end( $this->words );
$this->cur_word = (string) end( $this->words );
if ( '' !== $this->cur_word && ! preg_match( '/^\-/', $this->cur_word ) ) {
array_pop( $this->words );
}
Expand Down Expand Up @@ -178,10 +178,8 @@ private function get_global_parameters() {
* Store individual option.
*
* @param string $opt Option to store.
*
* @return void
*/
private function add( $opt ) {
private function add( $opt ): void {
if ( '' !== $this->cur_word ) {
if ( 0 !== strpos( $opt, $this->cur_word ) ) {
return;
Expand Down
11 changes: 8 additions & 3 deletions php/WP_CLI/Configurator.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
}

$env_files = getenv( 'WP_CLI_REQUIRE' )
? array_filter( array_map( 'trim', explode( ',', getenv( 'WP_CLI_REQUIRE' ) ) ) )
? array_filter( array_map( 'trim', explode( ',', (string) getenv( 'WP_CLI_REQUIRE' ) ) ) )

Check warning on line 89 in php/WP_CLI/Configurator.php

View check run for this annotation

Codecov / codecov/patch

php/WP_CLI/Configurator.php#L89

Added line #L89 was not covered by tests
: [];

if ( ! empty( $env_files ) ) {
Expand Down Expand Up @@ -140,7 +140,12 @@
$runtime_alias = getenv( 'WP_CLI_RUNTIME_ALIAS' );
if ( false !== $runtime_alias ) {
$returned_aliases = [];
foreach ( json_decode( $runtime_alias, true ) as $key => $value ) {

/**
* @var string $key
* @var array<string, string> $value
*/
foreach ( (array) json_decode( $runtime_alias, true ) as $key => $value ) {

Check warning on line 148 in php/WP_CLI/Configurator.php

View check run for this annotation

Codecov / codecov/patch

php/WP_CLI/Configurator.php#L148

Added line #L148 was not covered by tests
if ( preg_match( '#' . self::ALIAS_REGEX . '#', $key ) ) {
$returned_aliases[ $key ] = [];
foreach ( self::$alias_spec as $i ) {
Expand Down Expand Up @@ -277,7 +282,7 @@
$this->merge_yml( $inherit_path, $current_alias );
}
// Prepare the base path for absolutized alias paths.
$yml_file_dir = $path ? dirname( $path ) : false;
$yml_file_dir = $path ? dirname( $path ) : '';
foreach ( $yaml as $key => $value ) {
if ( preg_match( '#' . self::ALIAS_REGEX . '#', $key ) ) {
$this->aliases[ $key ] = [];
Expand Down
27 changes: 14 additions & 13 deletions php/WP_CLI/Context/Admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,8 @@ function () {
*
* A lot of premium plugins/themes have their custom update routines locked
* behind an is_admin() call.
*
* @return void
*/
private function log_in_as_admin_user() {
private function log_in_as_admin_user(): void {
// TODO: Add logic to find an administrator user.
$admin_user_id = 1;

Expand Down Expand Up @@ -92,10 +90,8 @@ private function log_in_as_admin_user() {
* @global string $pagenow
* @global int $wp_db_version
* @global array $_wp_submenu_nopriv
*
* @return void
*/
private function load_admin_environment() {
private function load_admin_environment(): void {
global $hook_suffix, $pagenow, $wp_db_version, $_wp_submenu_nopriv;

if ( ! isset( $hook_suffix ) ) {
Expand All @@ -104,28 +100,33 @@ private function load_admin_environment() {

// Make sure we don't trigger a DB upgrade as that tries to redirect
// the page.
$wp_db_version = (int) get_option( 'db_version' ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited

/**
* @var string $wp_db_version
*/
$wp_db_version = get_option( 'db_version' ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
$wp_db_version = (int) $wp_db_version; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited

// Ensure WP does not iterate over an undefined variable in
// `user_can_access_admin_page()`.
if ( ! isset( $_wp_submenu_nopriv ) ) {
$_wp_submenu_nopriv = []; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
}

$admin_php_file = file_get_contents( ABSPATH . 'wp-admin/admin.php' );
$admin_php_file = (string) file_get_contents( ABSPATH . 'wp-admin/admin.php' );

// First we remove the opening and closing PHP tags.
$admin_php_file = preg_replace( '/^<\?php\s+/', '', $admin_php_file );
$admin_php_file = preg_replace( '/\s+\?>$/', '', $admin_php_file );
$admin_php_file = (string) preg_replace( '/^<\?php\s+/', '', $admin_php_file );
$admin_php_file = (string) preg_replace( '/\s+\?>$/', '', $admin_php_file );

// Then we remove the loading of either wp-config.php or wp-load.php.
$admin_php_file = preg_replace( '/^\s*(?:include|require).*[\'"]\/?wp-(?:load|config)\.php[\'"]\s*\)?;\s*$/m', '', $admin_php_file );
$admin_php_file = (string) preg_replace( '/^\s*(?:include|require).*[\'"]\/?wp-(?:load|config)\.php[\'"]\s*\)?;\s*$/m', '', $admin_php_file );

// We also remove the authentication redirect.
$admin_php_file = preg_replace( '/^\s*auth_redirect\(\);$/m', '', $admin_php_file );
$admin_php_file = (string) preg_replace( '/^\s*auth_redirect\(\);$/m', '', $admin_php_file );

// Finally, we avoid sending headers.
$admin_php_file = preg_replace( '/^\s*nocache_headers\(\);$/m', '', $admin_php_file );
$admin_php_file = (string) preg_replace( '/^\s*nocache_headers\(\);$/m', '', $admin_php_file );
$_GET['noheader'] = true;

eval( $admin_php_file ); // phpcs:ignore Squiz.PHP.Eval.Discouraged
Expand Down
2 changes: 1 addition & 1 deletion php/WP_CLI/Context/Auto.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ private function deduce_best_context() {
*
* @return bool Whether the current command should be run as admin.
*/
private function is_command_to_run_as_admin() {
private function is_command_to_run_as_admin(): bool {
$command = WP_CLI::get_runner()->arguments;

foreach ( self::COMMANDS_TO_RUN_AS_ADMIN as $command_to_run_as_admin ) {
Expand Down
Loading