szepeviktor / phpstan-wordpress

WordPress extensions for PHPStan ⛏️
https://packagist.org/packages/szepeviktor/phpstan-wordpress
MIT License
269 stars 27 forks source link

Add type checking for hook callbacks in `add_action` and `add_filter` #106

Open johnbillion opened 2 years ago

johnbillion commented 2 years ago

I'm planning on working on some rules that check the use of add_action() and add_filter() when the action or filter is from WordPress core. The wp-hooks library facilitates this, and the wp-hooks-generator library facilitates this for hooks in third party plugins and themes (although I'm only concentrating on the WordPress core hooks for now).

I'll open a PR once I have something working.


When I call add_action( 'foo', $callback ) or add_filter( 'foo', $callback ):

Notes:

szepeviktor commented 2 years ago

High expectations! Thank you.

herndlm commented 2 years ago

This was completed, wasn't it? 🎉

szepeviktor commented 2 years ago

I do not follow the development :)

johnbillion commented 2 years ago

This was only partially completed, I'll open a follow-up issue with the details.

menno-ll commented 2 years ago

Hi there,

Awesome that this feature is added! We've just updated to the latest version for some of our projects. However, we've encountered an issue, which is mixed return types. We see that when using a filter which has a return type of mixed declared in the PHPDoc, phpstan does not detect any return type, throwing this error: Filter callback return statement is missing.

This happens on a function like this:


/**
 *
 * @param mixed $some_mixed_var
 * @return mixed
 */
function some_function_with_mixed_return_type ( $some_mixed_var ) {
    $some_mixed_var = is_string( $some_mixed_var ) ? 'I am a string' : $some_mixed_var;
    return $some_mixed_var;
}
add_filter( 'some_filter_name', 'some_function_with_mixed_return_type' );

I hope you guys can take a look if we can resolve this :). That would save us from ignoring these errors which are actually important.

CC @sheila-levellevel

menno-ll commented 2 years ago

Also one extra thing, which is more an opinion i would like to start a little discussion about.

When creating a callback function for an action, with this new set of rules, a return type of void is forced for that function. However, because of it beeing an action, nothing would happen if you would let the callback function return a value. So why do I bring this up? It's because in some occasions, you would like to use the callback function in another place in your project. And there, you actually want to use the return variable. And this is now not possible.

An example below:


add_action( 'save_post', 'set_custom_meta' );
function set_custom_meta( int $post_id ): bool {
    return (bool) update_post_meta( $post_id, 'some_meta', 'some_value' );
}

function some_function_somewhere_else_in_the_website(): void {
    $meta_updated = set_custom_meta( 1 );
    if ( $meta_updated ) {
        // Do something
    } else {
        // Do something
    }
}

As you can see, this example is not possible, because we are now forced to return a void for the set_custom_meta function. A way around this issue is to create a separate function for both occasions, one returning a void, and the other returning the boolean. But that sounds as a workaround that's not needed. I would love to hear you guy's opinions. Thanks in advance!

CC @sheila-levellevel

johnbillion commented 2 years ago

@menno-ll Are you using version 1.1.5? Issues with mixed should have been fixed in that version. If so, can you open a new issue please?

Regarding returning a value from an action, I can see how it's beneficial to reuse functions but at the same time a developer looking at your set_custom_meta() function would, rightfully, expect its return value to be used, which is not true, and can cause confusion. This is the sort of strictness that PHPStan rules are intended to address. I recommend introducing a simple wrapper function that calls set_custom_meta() and use that in your action.

menno-ll commented 2 years ago

Hi @johnbillion

Thank you for the quick response!

You were right, we made the discovery with the mixed return type the day before v1.1.5 came out, and did not notice there was a new version where it was fixed. And yesterday I did not notice that v1.1.5 contained the fix, as it was not mentioned in the description of that release. I've upgraded to v1.1.5 and can confirm this resolved the issue. Thanks for pointing it out! No new issue is needed.

Regarding the reuse of a function used as an action callback, the way you describe with creating a wrapper function was also what i had in mind to bypass the phpstan error. I just wanted to make you aware of this scenario we found in our code, so it could be taken into consideration. If writing a wrapper function is the way to go, we will modify it to comply with the new rule, or ignore that rule for our projects, depending on the opinion of my collegues.

Thanks again for helping out!