phpstan-wordpress icon indicating copy to clipboard operation
phpstan-wordpress copied to clipboard

have_posts() is an impure function!

Open szepeviktor opened this issue 4 years ago • 9 comments

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()
    {
    }
}

szepeviktor avatar Apr 27 '21 18:04 szepeviktor

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

dingo-d avatar Dec 15 '21 14:12 dingo-d

Is this related to why the PHPStan reports for this:

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

szepeviktor avatar Dec 15 '21 16:12 szepeviktor

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

dingo-d avatar Dec 15 '21 17:12 dingo-d

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?

jeherve avatar Dec 15 '21 17:12 jeherve

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

dingo-d avatar Dec 15 '21 17:12 dingo-d

wordpress-stubs.txt

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

szepeviktor avatar Dec 15 '21 18:12 szepeviktor

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 ;)

janw-me avatar Jan 27 '22 15:01 janw-me

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 avatar Jan 27 '22 16:01 szepeviktor

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!

szepeviktor avatar Jan 27 '22 16:01 szepeviktor

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?

herndlm avatar Feb 13 '23 08:02 herndlm

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

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

szepeviktor avatar Feb 13 '23 08:02 szepeviktor

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

szepeviktor avatar Feb 14 '23 19:02 szepeviktor