Skip to content

Docs: Add refined string types to PHPStan return and parameter types - #13892

Closed
swissspidy wants to merge 22 commits into
WordPress:trunkfrom
swissspidy:fix/phpstan-strings
Closed

swissspidy wants to merge 22 commits into
WordPress:trunkfrom
swissspidy:fix/phpstan-strings

Conversation

@swissspidy

@swissspidy swissspidy commented Oct 1, 2026 •

Copy link
Copy Markdown
Member

✅ Committed in r64235 (f670e8a).


Split out of #13530, as proposed in this comment (subset 5).

  • Return types. non-empty-string, non-falsy-string and lowercase-string are added where the function always produces such a string. Examples are the admin markup helpers, trailingslashit(), path_join(), wp_get_wp_version(), the shortcode regexes, wp_json_encode(), wp_create_nonce() and wp_hash().
  • Parameter types. Four parameters are narrowed where the function rejects an empty value: wp_register_ability() $name, register_post_type() $post_type, add_shortcode() $tag and wp_upload_bits() $name.

Changes from #13530

These follow the review analysis:

  • Left out: non-falsy-string on register_rest_route()'s $route_namespace and $route. Every controller passes $this->namespace, which is typed string, so this alone accounted for 88 new errors at level 10.
  • Left out: non-empty-string on the $hook_name parameter of apply_filters(), do_action() and the related functions. Core passes plain strings to them in several places, including wp-cron.php. As the comment suggested, these parameter narrowings are better handled separately from the return types.

Changes after review

  • Dropped: non-empty-string|false on current_filter() and current_action(). Since apply_filters() and do_action() don't reject an empty hook name, '' can be the current filter. This belongs with the $hook_name narrowing above.
  • register_post_type()'s $post_type is lowercase-string&non-falsy-string, since the function also rejects '0'. wp_upload_bits() keeps non-empty-string, because non-falsy-string would flag the XML-RPC caller, which only guards against ''.
  • In wp_upload_bits(), @phpstan-param now comes before @phpstan-return, as everywhere else in core.

Effect on the analysis

composer run phpstan passes with no baseline changes. At level 10, compared against trunk, 17 errors are fixed and 21 are introduced. Most of the 21 are existing errors reworded with the narrower type. The rest are return.type errors where PHPStan cannot infer the refinement from the function body, for example a static cache in get_html_split_regex() and sprintf() in wp_generate_uuid4(). (These counts were measured before the changes after review, which remove the current_filter() error among the 21.)

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: Splitting #13530 by tag kind, applying the corrections from the review analysis on #13530 and from review on this PR, checking each subset with composer run phpstan (also at level 10, compared against trunk) and phpcs, and drafting the commit messages and this description. Reviewed by me.


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

https://claude.ai/code/session_015BuoHZQvJMvPEYp4Sfjgvd

Adds `non-empty-string`, `non-falsy-string` and `lowercase-string` return types where the function always produces such a string, and narrows a few parameters whose function rejects an empty value: `wp_register_ability()`, `register_post_type()`, `add_shortcode()` and `wp_upload_bits()`.

The map's `non-empty-string` on the `$hook_name` parameter of the hook functions and `non-falsy-string` on `register_rest_route()` are left out, since core itself passes plain strings to them.

See #65817.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VieGtSQtUoVfHiGwTmkvtc
Copilot AI balanced review requested due to automatic review settings October 1, 2026 09:01
@github-actions

github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Unlinked Accounts

The following contributors have not linked their GitHub and WordPress.org accounts: @claude.

Contributors, please read how to link your accounts to ensure your work is properly credited in WordPress releases.

Core Committers: Use this line as a base for the props when committing in SVN:

Props swissspidy, westonruter.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown

Test using WordPress Playground

The 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

  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Several parameter and hook-return refinements do not match values handled by the implementations.

Review effort: Balanced
Findings: 3 Medium severity

Open (3)
What changed in this PR

Adds refined PHPStan string types to core DocBlocks without changing runtime behavior.

Changes:

  • Narrows selected string parameters.
  • Refines helper return types for non-empty, non-falsy, and lowercase strings.
  • Improves static analysis across APIs, markup helpers, hashes, and regex generators.
File Description
src/​wp-includes/​shortcodes.php Refines shortcode parameter and regex types.
src/​wp-includes/​script-loader.php Refines script-tag output.
src/​wp-includes/​rewrite.php Refines feed hook output.
src/​wp-includes/​post.php Narrows post-type names.
src/​wp-includes/​plugin.php Refines current hook names.
src/​wp-includes/​pluggable.php Refines nonce and hash outputs.
src/​wp-includes/​link-template.php Types internal hosts as lowercase.
src/​wp-includes/​functions.php Refines utility parameters and returns.
src/​wp-includes/​formatting.php Refines regex, slug, and path outputs.
src/​wp-includes/​class-wp-widget.php Refines widget field identifiers.
src/​wp-includes/​class-wp-dependencies.php Refines ETag output.
src/​wp-includes/​class-wp-ajax-response.php Refines XML response output.
src/​wp-includes/​blocks.php Refines pagination-arrow markup.
src/​wp-includes/​block-template-utils.php Refines export-file paths.
src/​wp-includes/​block-supports/​elements.php Refines generated class names.
src/​wp-includes/​abilities-api.php Narrows ability names.
src/​wp-admin/​includes/​widgets.php Refines body-class output.
src/​wp-admin/​includes/​template.php Refines submit-button markup.
src/​wp-admin/​includes/​plugin.php Refines plugin-page hook names.
src/​wp-admin/​includes/​ms.php Refines help-sidebar markup.
src/​wp-admin/​includes/​media.php Refines media form markup.
src/​wp-admin/​includes/​class-wp-comments-list-table.php Refines avatar markup.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/wp-includes/functions.php
Comment thread src/wp-includes/plugin.php Outdated
Comment thread src/wp-includes/post.php Outdated

Copy link
Copy Markdown
Member Author

🤖 Comment by Claude Opus 5.5

Props for this subset, gathered from the full history of functionMap.php in php-stubs/wordpress-stubs. A change counts only where it introduced or changed the specific tag this PR carries, not just any change to the function's map entry. Purely mechanical changes are left out: tag key renames (php-stubs/wordpress-stubs#420), parameter renames (php-stubs/wordpress-stubs#115), coding standards (php-stubs/wordpress-stubs#119) and the duplicate-code refactor (php-stubs/wordpress-stubs#85).

Stubs change Author Entries
php-stubs/wordpress-stubs#227 @IanDelMar wp_json_encode()
php-stubs/wordpress-stubs#297 @IanDelMar get_shortcode_atts_regex(), get_shortcode_regex()
php-stubs/wordpress-stubs#303 @IanDelMar get_html_split_regex()
php-stubs/wordpress-stubs#305 @IanDelMar trailingslashit()
php-stubs/wordpress-stubs#307 @IanDelMar get_comments_pagination_arrow(), get_query_pagination_arrow()
php-stubs/wordpress-stubs#311 @IanDelMar wp_get_script_tag()
php-stubs/wordpress-stubs#315 @IanDelMar wp_widgets_access_body_class()
php-stubs/wordpress-stubs#317 @IanDelMar image_link_input_fields()
php-stubs/wordpress-stubs#318 @IanDelMar wp_caption_input_textarea()
php-stubs/wordpress-stubs#320 @IanDelMar wp_media_insert_url_form()
php-stubs/wordpress-stubs#321 @IanDelMar get_site_screen_help_sidebar_content()
php-stubs/wordpress-stubs#324 @IanDelMar get_plugin_page_hookname()
php-stubs/wordpress-stubs#329 @IanDelMar wp_generate_uuid4()
php-stubs/wordpress-stubs#331 @IanDelMar wp_fast_hash(), wp_hash()
php-stubs/wordpress-stubs#341 @IanDelMar sanitize_title_with_dashes()
php-stubs/wordpress-stubs#350 @IanDelMar wp_create_nonce()
php-stubs/wordpress-stubs#351 @IanDelMar wp_internal_hosts()
php-stubs/wordpress-stubs#362 @IanDelMar WP_Dependencies::get_etag()
php-stubs/wordpress-stubs#377 @IanDelMar add_shortcode()
php-stubs/wordpress-stubs#380 @IanDelMar register_post_type()
php-stubs/wordpress-stubs#384 @IanDelMar wp_get_wp_version()
php-stubs/wordpress-stubs#396 @IanDelMar add_feed()
php-stubs/wordpress-stubs#398 @IanDelMar current_action(), current_filter()
php-stubs/wordpress-stubs#422 @IanDelMar get_submit_button()
php-stubs/wordpress-stubs#423 @IanDelMar get_media_item()
php-stubs/wordpress-stubs#426 @IanDelMar WP_Widget::get_field_id(), WP_Widget::get_field_name()
php-stubs/wordpress-stubs#430 @IanDelMar wp_register_ability()
php-stubs/wordpress-stubs#434 @IanDelMar wp_get_elements_class_name()
php-stubs/wordpress-stubs#435 @IanDelMar wp_upload_bits()
php-stubs/wordpress-stubs#451 @IanDelMar wp_generate_block_templates_export_file()
php-stubs/wordpress-stubs#452 @IanDelMar WP_Ajax_Response::add()
php-stubs/wordpress-stubs#474 @IanDelMar WP_Comments_List_Table::floated_admin_avatar()
php-stubs/wordpress-stubs#476 @IanDelMar wp_get_elements_class_name()
php-stubs/wordpress-stubs#481 @IanDelMar path_join()

Props for this PR (swissspidy for the split, westonruter for the review that shaped it):

swissspidy, westonruter, marian1

Generated by Claude Code

claude added 3 commits October 5, 2026 15:46
Drop the non-empty-string return type from current_filter() and current_action(), since apply_filters() and do_action() do not reject an empty hook name. Use non-falsy-string for register_post_type(), which rejects '0' as well, and place @phpstan-param before @phpstan-return in wp_upload_bits().

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015BuoHZQvJMvPEYp4Sfjgvd
@swissspidy
swissspidy requested a review from westonruter October 7, 2026 13:11
westonruter and others added 18 commits October 7, 2026 11:25
PHPStan cannot see that requiring `version.php` assigns the static
`$wp_version`, so the return value was inferred as `mixed`, which
conflicts with the `non-falsy-string` return type. An inline `@var`
after the `require` asserts the type. A `@global` tag would not work,
since the function deliberately avoids the global.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The untyped static was inferred as `mixed`, which conflicts with the
`non-falsy-string` return type. Annotating it as
`non-falsy-string|null` lets PHPStan narrow it to `non-falsy-string`
by the time it is returned.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PHPStan loses the `lowercase-string` type established by `strtolower()`
once the title passes through `str_replace()` and `preg_replace()`, so
the return value was inferred as `string`. At runtime only lowercase
characters can remain after the `[^%a-z0-9 _-]` replacement, so an
inline `@var` asserts the declared return type.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The untyped static `$internal_hosts` was inferred as `mixed`, which
conflicts with the declared return type. Annotating the static fixes
that, since `array_map( 'strtolower', … )` already yields lowercase
strings.

The result of `array_unique()` is also passed through `array_values()`,
so that the function returns a `list` even when a filter adds a
duplicate host. Callers only check membership with `in_array()`, so
the reindexing does not affect them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PHPStan infers `non-falsy-string` from the `sprintf()` format, but does
not know that the `%x` conversion only produces lowercase hex digits.
The result is now assigned to a variable with an inline `@var`, so
that it matches the declared `lowercase-string&non-falsy-string` return
type.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The conditional return type of `path_is_absolute()` narrows its result
but not its argument, so the early `return $path;` in `path_join()` was
inferred as `string`, which conflicts with its `non-falsy-string` return
type. Every path that returns true requires a path that is neither empty
nor `'0'`, so `@phpstan-assert-if-true` narrows `$path` accordingly. The
false branch is left unnarrowed, since relative paths like `'../'` also
return false.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The key is documented as only containing lowercase alphanumeric
characters, dashes, and underscores, and the function rejects empty
names. This matches the type the branch gives `register_post_type()`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The name is passed through `sanitize_key()`, so the registered status
is always lowercase, and every core call registers a lowercase literal.
This matches the type the branch gives `register_post_type()`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`WP_Abilities_Registry::register()` validates the name against
`/^[a-z0-9-]+\/[a-z0-9-]+$/`, so it now has the same
`lowercase-string&non-falsy-string` type as `wp_register_ability()`.

`wp_register_ability_category()` and
`WP_Ability_Categories_Registry::register()` validate the slug against
`/^[a-z0-9]+(?:-[a-z0-9]+)*$/`. That pattern accepts `'0'`, so the slug
is narrowed to `lowercase-string&non-empty-string`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`WP_Block_Bindings_Registry::register()` rejects uppercase characters
and requires a name matching `/^[a-z0-9-]+\/[a-z0-9-]+$/`, so it and
`register_block_bindings_source()` now take a
`lowercase-string&non-falsy-string`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`WP_Icon_Collections_Registry::register()` validates the slug against
`/^[a-z0-9]([a-z0-9_-]*[a-z0-9])?$/`. That pattern accepts `'0'`, so the
slug is narrowed to `lowercase-string&non-empty-string`.

`WP_Icons_Registry::register()` requires a namespaced name whose
collection is registered and whose icon name is lowercase, so the name
is narrowed to `lowercase-string&non-falsy-string`.

The wrapper functions get the same types. To keep the default icons
registered by `_wp_register_default_icons()` consistent with this, the
generated icon manifest is given an array shape with lowercase icon
names and collection slugs. This also resolves the `mixed` errors
previously reported for the manifest's label, collections, and keywords.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`WP_Connector_Registry::register()` validates the ID against
`/^[a-z0-9_-]+$/`. That pattern accepts `'0'`, so the ID is narrowed to
`lowercase-string&non-empty-string`.

The default AI providers are registered with IDs that come from the
AI Client, which PHPStan cannot see are lowercase. `ProviderMetadata`
already rejects IDs that are not lowercase, so an inline `@var` asserts
the type at that call site.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`WP_Block_Type_Registry::register()` rejects uppercase characters and
requires a name matching `/^[a-z0-9-]+\/[a-z0-9-]+$/`, so a string name
is narrowed to `lowercase-string&non-falsy-string`.

`register_block_type()` keeps a plain `string` parameter, since it also
accepts a path to block metadata. Once the path case has returned, the
remaining string should be a block type name, which an inline `@var`
asserts before it is passed to the registry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`WP_Block_Templates_Registry::register()` rejects uppercase characters
and requires a name matching `/^[a-z0-9_\-]+\/\/[a-z0-9_\-]+$/`, so it
and `register_block_template()` now take a
`lowercase-string&non-falsy-string`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`add_menu_page()`, `add_submenu_page()`, and the `add_*_page()` helpers
now take a `non-falsy-string` menu slug. The slug is not narrowed to
lowercase, even though the documentation says it should be: established
plugins register mixed-case slugs that appear in admin URLs, so they
cannot be changed without breaking existing links.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The shape uses PHPStan-only types such as `lowercase-string` and
`non-empty-list`, so it belongs in a `@phpstan-` prefixed tag, where
other tools that read docblocks will not misinterpret it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This reverts the switch to `@phpstan-var`. Inline annotations on local
variables are not part of the developer documentation, and core already
uses plain `@var` with array shapes for them, as in `blocks.php`. The
`@phpstan-` prefix is only needed in docblocks that document a symbol.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@westonruter westonruter left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚢

@swissspidy

Copy link
Copy Markdown
Member Author

@westonruter please feel free to commit :)

wporg-sync pushed a commit that referenced this pull request Oct 7, 2026
Adds `non-empty-string`, `non-falsy-string`, and `lowercase-string` return types where a function always produces such a string, mostly taken from [https://github.com/php-stubs/wordpress-stubs php-stubs/wordpress-stubs]. Where PHPStan cannot infer the refinement from the function body, such as from a static cache or a `sprintf()` call, the type is asserted inline so that the narrower types introduce no new errors.

Registration functions now require a lowercase key where it is documented or validated as lowercase. This covers post types, post statuses, and taxonomies, as well as the names used by the abilities, block bindings, block types, block templates, connectors, and icons registries. Static analysis describes what callers should supply, so these follow the documented contract even where a function lowercases the key itself. Admin menu slugs are only narrowed to `non-falsy-string`: although they are documented as lowercase, established plugins register mixed-case slugs which appear in admin URLs and cannot be changed without breaking links. Script and style handles are left as plain strings for the same reason, since mixed-case handles are widespread and other code must pass them verbatim as dependencies.

The only runtime change is in `wp_internal_hosts()`, which now re-indexes the deduplicated hosts with `array_values()` so that it returns a list.

Developed in #13892.
Follow-up to r55289, r64163.

Props marian1, swissspidy, westonruter.
See #65817.


git-svn-id: https://develop.svn.wordpress.org/trunk@64235 602fd350-edb4-49c9-b593-d223f7449a82
@westonruter westonruter closed this Oct 7, 2026
wporg-sync pushed a commit to WordPress/WordPress that referenced this pull request Oct 7, 2026
Adds `non-empty-string`, `non-falsy-string`, and `lowercase-string` return types where a function always produces such a string, mostly taken from [https://github.com/php-stubs/wordpress-stubs php-stubs/wordpress-stubs]. Where PHPStan cannot infer the refinement from the function body, such as from a static cache or a `sprintf()` call, the type is asserted inline so that the narrower types introduce no new errors.

Registration functions now require a lowercase key where it is documented or validated as lowercase. This covers post types, post statuses, and taxonomies, as well as the names used by the abilities, block bindings, block types, block templates, connectors, and icons registries. Static analysis describes what callers should supply, so these follow the documented contract even where a function lowercases the key itself. Admin menu slugs are only narrowed to `non-falsy-string`: although they are documented as lowercase, established plugins register mixed-case slugs which appear in admin URLs and cannot be changed without breaking links. Script and style handles are left as plain strings for the same reason, since mixed-case handles are widespread and other code must pass them verbatim as dependencies.

The only runtime change is in `wp_internal_hosts()`, which now re-indexes the deduplicated hosts with `array_values()` so that it returns a list.

Developed in WordPress/wordpress-develop#13892.
Follow-up to r55289, r64163.

Props marian1, swissspidy, westonruter.
See #65817.

Built from https://develop.svn.wordpress.org/trunk@64235


git-svn-id: http://core.svn.wordpress.org/trunk@63386 1a063a9b-81f0-0310-95a4-ce76da25c4cd
@swissspidy
swissspidy deleted the fix/phpstan-strings branch October 7, 2026 20:57
* @param int $comment_id Comment ID.
* @return string Avatar with the user name.
*
* @phpstan-return non-falsy-string

@dmsnell dmsnell Oct 7, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems like we have been adding a lot of aspirational, but wrong type annotations lately, and I’m really concerned about the choices we’re making in response to PHPStan warnings.

is it not obvious by inspection that this can return a false string? maybe I’m wrong, but it seems like get_comment() can return null and get_avatar() can return false, which leads to string(1) " " which itself is falsy.

if this is the case, these more-frequent invalid type annotations only hide type errors and make them harder to find, and they taint the type checking even further by asserting that the type is not what the code says, but that there is some reason to trust us rather than the code.

at least this won’t case crashes, being the docblock annotation, but it can still cause headaches when debugging why a false appears where the type system claims it cannot

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, " " is truthy: https://3v4l.org/Ft5fq#veol

Otherwise, if it had indeed been falsy, then an aspirational type would be wrong.

If there is any other example which is aspirational you see, I'm happy to revisit!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the choices we’re making in response to PHPStan warnings.

Also, most of these narrowed types here are not to address any warnings. They are intended to improve correctness so that callers and callees have as specific type information available.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for refuting me on that @westonruter

mostly it’s with these dependent-type annotations like non-empty-string or non-empty-array — these seem frail, and by aspirational I mean it’s what we expect, but not necessarily what can occur.

I tend to skip over these without too much thought, and maybe every time I see them I’m wrong, so I’ll try and pay more attention, though I definitely cannot keep up with the pace of PHPStan changes.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dmsnell The hope is that you won't have to think about these. We can offload the thinking to PHPStan. If the method here is ever modified to do something like this instead:

diff --git a/src/wp-admin/includes/class-wp-comments-list-table.php b/src/wp-admin/includes/class-wp-comments-list-table.php
index 7294f89d1b..419427b6ce 100644
--- a/src/wp-admin/includes/class-wp-comments-list-table.php
+++ b/src/wp-admin/includes/class-wp-comments-list-table.php
@@ -68,7 +68,7 @@ class WP_Comments_List_Table extends WP_List_Table {
 	public function floated_admin_avatar( $name, $comment_id ) {
 		$comment = get_comment( $comment_id );
 		$avatar  = get_avatar( $comment, 32, 'mystery' );
-		return "$avatar $name";
+		return $avatar . $name;
 	}
 
 	/**

Then PHPStan would raise an error here:

  71     Method WP_Comments_List_Table::floated_admin_avatar() should return non-falsy-string but returns string.                                                  
         🪪  return.type                                                                                                                                           
         at src/wp-admin/includes/class-wp-comments-list-table.php:71    

In this way, I don't think they are frail. They are being checked for their truthfulness (and truthiness!)

The hope is that having these narrowed types will allow users of the method to avoid dead code. For example, if someone did this:

$avatar = $list_table->floated_admin_avatar( 'John Smith', 1 );
if ( $avatar ) {
	echo "<div>$avatar</div>";
} else {
	echo "<div>NO AVATAR!</div>"; // DEAD CODE!
}

Then PHPStan can flag the if() condition as an if.alwaysTrue error.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then PHPStan would raise an error here…don’t think they are frail

if we’re overly conservative that seems fine, but we are seeming to be overly-optimistic in these situations.

it seems that either way, in this case with the comment and avatar, things are not changed, but some strings are falsey, like "0". and I think the abs_int() example is illustrative.

PHP and WP code generally has done a poor job of indicating the real possible types. I understand PRs like this exist to improve that situation.

in the example, I think the conflation of types inside floated_admin_avatar() is more of the problem than the if ( $avatar ) (though I would agree it’s also a problem). it would seem more robust to perform the checks within floated_admin_avatar() and return a positive signal of failure rather than an implicit behavior, e.g. string|null.

in this particular case I mis-identified the type as being wrong, so it’s not important to focus on it. that was my mistake.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants