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: |
|
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:
- Update the
@returnannotation to replacevoidwithnull(or remove|voidwhere the function always returns a typed value) - Change bare
return;statements toreturn null; - 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|voidis arguably correct — terminates whenexit=true, returns whenexit=false. No change needed.escape(): Returns string for scalar, modifies by-reference for array. Unusual pattern.set_spacing_sizes():null|voidis redundant — both mean "no value". Should be justnull.wp_trash_post_comments(): Returnsint|falseon success, bare return on failure. Should beint|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)
This ticket was mentioned in PR #11012 on WordPress/wordpress-develop by @apermo.
3 weeks ago
#1
- Keywords has-patch added
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.
@nimeshatxecurify commented on PR #11013:
3 weeks ago
#3
Incomplete PR, closing in favor of #11012
@westonruter commented on PR #11012:
2 weeks ago
#6
@apermo Please double-check my additions.
@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.
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.