Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

[11.x] Update PHPStan to 2.x #53716

Merged
merged 7 commits into from
Feb 5, 2025
Merged

[11.x] Update PHPStan to 2.x #53716

merged 7 commits into from
Feb 5, 2025

Conversation

tamiroh
Copy link
Contributor

@tamiroh tamiroh commented Nov 30, 2024

PHPStan 2.0 has been released so this pull request updates PHPStan version to 2.x.

Most of the fixes are under types/.

Copy link

Thanks for submitting a PR!

Note that draft PR's are not reviewed. If you would like a review, please mark your pull request as ready for review in the GitHub user interface.

Pull requests that are abandoned in draft may be closed due to inactivity.

@tamiroh tamiroh changed the title [11.x] Use PHPStan 2.0 [11.x] Update PHPStan to 2.x Nov 30, 2024
@tamiroh tamiroh marked this pull request as ready for review November 30, 2024 13:15
@taylorotwell
Copy link
Member

All those hard-coded integers seem kinda weird?

@taylorotwell taylorotwell marked this pull request as draft November 30, 2024 22:33
@crynobone crynobone requested a review from nunomaduro December 10, 2024 08:18
@@ -258,6 +258,7 @@ public function run(array|string|null $command = null, ?callable $output = null)

return new ProcessResult(tap($process)->run($output));
} catch (SymfonyTimeoutException $e) {
/** @phpstan-ignore variable.undefined */
Copy link

Choose a reason for hiding this comment

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

Ignoring errors doesn't seem right.

Maybe move $process = $this->toSymfonyProcess($command); out of the try section instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed. Fixed in 7ce889a.

@@ -4,7 +4,7 @@

use function PHPStan\Testing\assertType;

new class implements ValidationRule
$class = new class implements ValidationRule
Copy link

Choose a reason for hiding this comment

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

Suggested change
$class = new class implements ValidationRule
new class implements ValidationRule

Copy link
Contributor Author

@tamiroh tamiroh Dec 22, 2024

Choose a reason for hiding this comment

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

The instance must be assigned to some variable to avoid the following error...

 ------ ----------------------------------------------------------------------------------------------------------------------------- 
  Line   ValidationRule.php                                                                                                           
 ------ ----------------------------------------------------------------------------------------------------------------------------- 
  7      Expression "new class implements \Illuminate\Contracts\Validation\ValidationRule…" on a separate line does not do anything.  
         🪪  expr.resultUnused                                                                                                        
 ------ ----------------------------------------------------------------------------------------------------------------------------- 

Copy link

Choose a reason for hiding this comment

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

The error is valid, but the real problem is something else

Looking at the entire file, it doesn't seem like it's testing anything. The class is being instantiated, but the assertion call is inside a method that isn't being called.

I'd rather see the test being reworked so there's a point in even having it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Certainly this assertion is not called when this code is executed, but when it is analyzed by PHPStan the assertion is performed. If the assertion results in an error, PHPStan reports it :).

Comment on lines +24 to 26
assertType('36', $cache->remember('cache', now(), function (): int {
return 36;
}));
Copy link

Choose a reason for hiding this comment

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

I would assume that a callback with int return type would result in a type called int and not 36. There seems to be a problem elsewhere.

All these type assertions should remain unchanged.

Copy link
Contributor Author

@tamiroh tamiroh Dec 22, 2024

Choose a reason for hiding this comment

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

I think that since PHPStan 2.0, types are inferred more narrowly, in this case as 36 literal type.

https://phpstan.org/writing-php-code/phpdoc-types#literals-and-constants

Copy link

Choose a reason for hiding this comment

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

I hope that's something that can be configured somewhere, since the returned type is a string with the number, so the "literal" part is misleading.

Copy link
Contributor

Choose a reason for hiding this comment

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

This points at a problem with the method signature which has to be fixed first. PHPStan really does no longer generalizes scalar values (going from 42 to int) because it causes problems with how people use generics.

When we look at the signature in question, it realy doesn't make much sense:

/**
* Get an item from the cache, or execute the given Closure and store the result.
*
* @template TCacheValue
*
* @param string $key
* @param \Closure|\DateTimeInterface|\DateInterval|int|null $ttl
* @param \Closure(): TCacheValue $callback
* @return TCacheValue
*/
public function remember($key, $ttl, Closure $callback)

You have no guarantee the value type in the cache will be the same as the type returned by the callback. This method should just return mixed because we don't know what's going to be in the cache.

I recommend stopping using generics for cases like these, TDefault etc.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also it occured to me this behaviour and this signature might be fine. If the closure returns "int" (for example it calls a function that has "int" return type), the infered TCacheValue will be "int".

If the Closure always returns "42" then it might actually be correct for TCacheValue to be "42", because nothing else will ever be written to the cache by the code, right?

Definitely some food for thought here :)

@tamiroh tamiroh requested a review from sydgren December 22, 2024 10:41
Copy link
Contributor

@ondrejmirtes ondrejmirtes left a comment

Choose a reason for hiding this comment

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

Would be great to get this over the finish line, as PHPStan needs Laravel repository for its own integration tests, to make sure it doesn't break anything :)

Comment on lines +24 to 26
assertType('36', $cache->remember('cache', now(), function (): int {
return 36;
}));
Copy link
Contributor

Choose a reason for hiding this comment

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

This points at a problem with the method signature which has to be fixed first. PHPStan really does no longer generalizes scalar values (going from 42 to int) because it causes problems with how people use generics.

When we look at the signature in question, it realy doesn't make much sense:

/**
* Get an item from the cache, or execute the given Closure and store the result.
*
* @template TCacheValue
*
* @param string $key
* @param \Closure|\DateTimeInterface|\DateInterval|int|null $ttl
* @param \Closure(): TCacheValue $callback
* @return TCacheValue
*/
public function remember($key, $ttl, Closure $callback)

You have no guarantee the value type in the cache will be the same as the type returned by the callback. This method should just return mixed because we don't know what's going to be in the cache.

I recommend stopping using generics for cases like these, TDefault etc.

@tamiroh
Copy link
Contributor Author

tamiroh commented Feb 2, 2025

There may be room for improvement, but the type tests under types/ and PHPDoc can be improved after the merge, and I think it is better to merge this pull request once for now 👀.

@tamiroh tamiroh marked this pull request as ready for review February 2, 2025 08:39
@taylorotwell taylorotwell merged commit 136a231 into laravel:11.x Feb 5, 2025
38 checks passed
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants