szepeviktor / phpstan-wordpress

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

have_posts() is an impure function! #42

Closed szepeviktor closed 1 year ago

szepeviktor commented 3 years ago
stubFiles:
    - tests/phpstan/wordpress-override.stub
<?php

/**
 * Whether current WordPress query has results to loop over.
 *
 * @since 1.5.0
 *
 * @global WP_Query $wp_query Global WP_Query instance.
 *
 * @return bool
 * @phpstan-impure
 */
function have_posts()
{
}

class WP_Query
{
    /**
     * Determines whether there are more posts available in the loop.
     *
     * Calls the {@see 'loop_end'} action when the loop is complete.
     *
     * @since 1.5.0
     *
     * @return bool True if posts are available, false if end of loop.
     * @phpstan-impure
     */
    public function have_posts()
    {
    }
}

https://github.com/phpstan/phpstan/discussions/8822

dingo-d commented 2 years ago

Is this related to why the PHPStan reports for this:

if ($query->have_posts()) {
    while ($query->have_posts()) {
        $query->the_post();

        $list[] = [
            'id' => \get_the_ID(),
            'title' => \get_the_title(),
            'url' => \get_permalink(),
        ];
    }
}
\wp_reset_postdata();

While loop condition is always true.

I got this notice in phpstan once I updated to phpstan v1

szepeviktor commented 2 years ago

Is this related to why the PHPStan reports for this:

Yes. have_posts changes its return value based on other methods of WP_Query.

dingo-d commented 2 years ago

Thanks, I'll just have to ignore this line per line 😅

jeherve commented 2 years ago

I'll just have to ignore this line per line

You could try to edit your phpstan.neon.dist to always ignore that warning, by targetting something like: message: '#While loop condition is always true#'

While it may catch other use-cases, it may help a bit instead of doing it line by line?

dingo-d commented 2 years ago

Yeah, I'd like not to ignore all those cases, because it might ignore legitimate notices 🙂 So one by one would be good alternative 😄

szepeviktor commented 2 years ago

wordpress-stubs.txt

Try with these stubs! It contains class-wp-query.php with all its source code.

janw-me commented 2 years ago

This isn't about WP_Query only if you wrap the while in the if it assumes it's true and always will untill the end of time. The same happens with the ACF function have_rows used by the repeater field.
The example below gives an error 3 out of 4 times.

<?php
// normal template
if ( have_posts() ) :
    while ( have_posts() ):
        the_post();
    endwhile;
else:
    echo 'fallback template';
endif;

// custom query
$query = new WP_Query();
if ( $query->have_posts() ) :
    while ( $query->have_posts() ):
        $query->the_post();
    endwhile;
else:
    echo 'fallback template';
endif;

// ACF > including https://github.com/php-stubs/acf-pro-stubs
if ( have_rows( 'featured' ) ):
    while ( have_rows( 'featured' ) ) :
        the_row();
    endwhile;
else:
    echo 'fallback template';
endif;

// Custom Query
// No if === no error
$query = new WP_Query();
while ( $query->have_posts() ):
    $query->the_post();
endwhile;

I'm willing to look into this although I have no experience with stanphp untill today... If someone has pointers I would appreciate it ;)

szepeviktor commented 2 years ago

I have no experience with stanphp untill today...

Hello Janw! PHPStan (not stanphp) is an OOP tool, it won't work with mysterious impure functions. Please add @phpstan-impure to all stubs that need it. There is sed for you!

sed -i -e 's#^\s*\* @return bool True if posts are available, false if end of the loop\.$#&\n     * @phpstan-impure#' vendor/php-stubs/wordpress-stubs/wordpress-stubs.php
szepeviktor commented 2 years ago

All I can think of is a new extension that flags these functions as impure. But that sounds like a nightmare. I'm not willing to spend my time on this. You know?! WordPress!

herndlm commented 1 year ago

Viktor did you handle this one already via 0c610fd or is this issue meant to be kept open for e.g. a more generic solution or something like that?

szepeviktor commented 1 year ago

I cannot answer. There are only wrong answers. This is a 📌 pinned issue.

https://github.com/phpstan/phpstan/discussions/8822

szepeviktor commented 1 year ago

It turns out it could be fixed without writing code! 👆🏻