close

Make WordPress Core

Opened 3 weeks ago

Last modified 2 weeks ago

#64704 new defect (bug)

Code Modernization: Replace void in PHPDoc union return types with null in various core files

Reported by: apermo's profile apermo Owned by:
Milestone: 7.0 Priority: normal
Severity: normal Version: 3.9
Component: General Keywords: has-patch
Focuses: Cc:

Description

Following up on #64694 which fixed paginate_links(), this ticket addresses 34 instances across various wp-includes files where @return annotations incorrectly use void as part of a union type.

The |void pattern in these files spans from WordPress 3.9 (unregister_default_headers()) through WordPress 6.8 (handle_error(), WP_Widget::form()), with two instances on unreleased trunk (wp_die(), print_late_styles()). The bulk originated in WordPress 4.3 via [32568] — "Use void instead of null where appropriate when pipe-delimiting @return types".

Why this matters

In PHP's type system, void means "the function does not return a value" and cannot be part of a union type (this is a compile error in PHP 8.0+). When a function uses bare return; or falls off the end without returning, the actual runtime value is null. Therefore @return Type|void should be @return Type|null.

This affects:

  • Static analysis tools (PHPStan, Psalm)
  • IDE autocompletion and type inference
  • Developer expectations about return values

Backward Compatibility

This is a safe, non-breaking change. As demonstrated by @westonruter in the #64694 PR review, return; and return null; are identical at runtime across every PHP version from 4.3.0 through 8.5.3: https://3v4l.org/3KQC8

Proposed Changes

For each instance:

  1. Update the @return annotation to replace void with null (or remove |void where the function always returns a typed value)
  2. Change bare return; statements to return null;
  3. Update description text to say "null" instead of "void" / "nothing"

Affected Functions

File Function Line Current Recommendation Since
functions.php wp_ext2type() 2997 string|void string|null 4.3
functions.php wp_die() 3767 never|void No change needed trunk
functions.php wp_update_php_annotation() 8556 string|void string|null 6.4
capabilities.php add_role() 1133 WP_Role|void WP_Role|null 6.1
class-wp-roles.php add_role() 174 WP_Role|void WP_Role|null 6.1
formatting.php sanitize_hex_color() 6235 string|void string|null 4.6
canonical.php redirect_canonical() 40 string|void string|null 4.3
revision.php wp_save_post_revision() 128 int|WP_Error|void int|WP_Error|null 4.3
class-wp-scripts.php print_scripts_l10n() 204 bool|string|void bool|string|null 6.1
class-wp-scripts.php print_extra_script() 220 bool|string|void bool|string|null 6.1
script-loader.php print_late_styles() 2374 string[]|void string[]|null trunk
ms-functions.php get_active_blog_for_user() 43 WP_Site|void WP_Site|null 4.5
ms-functions.php add_existing_user_to_blog() 2272 true|WP_Error|void true|WP_Error|null 5.4
class-wp-block-type.php __get() 361 string|string[]|null|void string|string[]|null 6.2
class-wp-plugin-dependencies.php get_dependency_api_data() 646 array|void array|null 6.5
class-wp-recovery-mode.php handle_error() 164 true|WP_Error|void true|WP_Error|null 6.8
class-wp-xmlrpc-server.php escape() 356 string|void string|null 4.3
class-wp-theme-json.php set_spacing_sizes() 4270 null|void null (redundant) 6.1
class-wp-style-engine-css-rules-store.php get_store() 54 WP_Style_Engine_CSS_Rules_Store|void ...|null 6.1
class-wp-style-engine-css-rules-store.php add_rule() 131 WP_Style_Engine_CSS_Rule|void ...|null 6.3
widgets.php wp_widget_description() 449 string|void string|null 4.4
widgets.php wp_sidebar_description() 474 string|void string|null 4.4
class-wp-widget.php WP_Widget::form() 141 string|void string (void incorrect) 6.8
theme.php remove_theme_support() 3064 bool|void bool (void incorrect) 4.3
theme.php unregister_default_headers() 1623 bool|void bool|null 3.9
media.php wp_audio_shortcode() 3392 string|void string|null 4.3
media.php wp_video_shortcode() 3617 string|void string|null 4.3
media.php wp_prepare_attachment_for_js() 4467 array|void array|null 5.6
post.php get_post_custom_keys() 2853 array|void array|null 4.4
post.php wp_trash_post_comments() 4218 mixed|void int|false|null 4.4
post.php wp_untrash_post_comments() 4279 true|void true|null 4.4
comment.php wp_update_comment_count() 2809 bool|void bool|null 4.5
comment.php trackback() 3316 int|false|void int|false|null 4.4

Notes on special cases

  • wp_die(): never|void is arguably correct — terminates when exit=true, returns when exit=false. No change needed.
  • escape(): Returns string for scalar, modifies by-reference for array. Unusual pattern.
  • set_spacing_sizes(): null|void is redundant — both mean "no value". Should be just null.
  • wp_trash_post_comments(): Returns int|false on success, bare return on failure. Should be int|false|null.
  • wp_untrash_post_comments(): Returns true, bare return, or falls off end. Possible bug at end of function.
  • unregister_default_headers(): Returns bool for single header, void for array input (recursive). Oldest instance (WP 3.9).

See #64694 for prior art.

Change History (7)

Image

This ticket was mentioned in PR #11012 on WordPress/wordpress-develop by @apermo.


3 weeks ago
#1

  • Keywords has-patch added

Co-Authored-By: xateman

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

## Use of AI Tools

Used AI for research, documentation and for the replacements. Everything was reviewed by myself and @xateman before opening this PR.

Image

This ticket was mentioned in PR #11013 on WordPress/wordpress-develop by @nimeshatxecurify.


3 weeks ago
#2

Updates various functions to explicitly return null instead of implicitly returning void when no specific value is meant to be returned.

This change improves type consistency and clarity, better reflecting the function's actual behavior and aligning with modern PHP type-hinting practices.

Image

@nimeshatxecurify commented on PR #11013:


3 weeks ago
#3

Incomplete PR, closing in favor of #11012

#4 Image @apermo
3 weeks ago

Props: @xate

Co-Authored and Reviewed

#5 Image @westonruter
2 weeks ago

  • Milestone changed from Awaiting Review to 7.0

Image

@westonruter commented on PR #11012:


2 weeks ago
#6

@apermo Please double-check my additions.

Image

@apermo commented on PR #11012:


2 weeks ago
#7

@westonruter all checked, ran your stricter phpstan.neon on the changes. And resolved all covered issues to remove clutter from the UI.

Note: See TracTickets for help on using tickets.