Narrow type with phpstan-assert even if we don't directly call the method for some Symfony class/interfaces.
VincentLanglet opened this issue · 6 comments
I recently got an idea for the following issue #179
For context, Symfony expose code which can resume to this:
abstract class Voter
{
public function vote(string $attribute, $subject, $token): bool {
if ($this->supports($attribute, $subject) {
return $this->voteOnAttribute($attribute, $subject, $token);
}
}
abstract protected function supports(string $attribute, $subject): bool;
abstract protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool;
}
So I'd like that, if I write
class MyVoter extends Voter
{
/**
* @phpstan-assert-if-true User $subject
* @phpstan-assert-if-true 'a'|'b' $attribute
*/
protected function supports(string $attribute, $subject): bool
{
return $subject instanceof User && in_array($attribute, ['a', 'b']);
}
protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
{
// I'd like phpstan to narrow $attribute, $subject like if I made the
// if ($this->supports($attribute, $subject) {
// call by myself
}
}
Do you think it's possible with some TypeSpecifier @ondrejmirtes ? I'm not familiar with this part of PHPStan.
If this logic is possible this could be later generalize to lot of other Symfony interfaces/classes.
- Why do you want to write a type-specifying extension if you're showing the example with
@phpstan-assert-if-truethat should also work? - Sure, what's possible with
@phpstan-assert*is also possible with type-specifying extension, and more, that's been true since the beginning :)
- Why do you want to write a type-specifying extension if you're showing the example with
@phpstan-assert-if-truethat should also work?
Because it doesn't work like this https://phpstan.org/r/fb87f7e8-5e3d-4026-98a6-338fe3162b67
That doesn't make sense to me - you have no guarantee someone will call supports before calling voteOnAttribute.
But if you want to enforce that, you can: https://phpstan.org/r/bc1e9de0-3dcb-466d-8b0d-e823a3c9f12f
That doesn't make sense to me - you have no guarantee someone will call supports before calling voteOnAttribute.
That's why I opened the issue in the Symfony plugin, because this specific class have the following comment:
"It is safe to assume that $attribute and $subject already passed the "supports()" method check."
Symfony provide a lot of classes with a supports method and I wanted to find a way to support this architecture.
But if you want to enforce that, you can: phpstan.org/r/bc1e9de0-3dcb-466d-8b0d-e823a3c9f12f
With this, you have a strict-rule error for contravariant issues https://phpstan.org/r/b72f4692-b3a2-4281-93de-a8f740e5ce75 I wanted to avoid.
There's no extension to change the current behaviour now.
With this, you have a strict-rule error for contravariant issues
Generics to the rescue: https://phpstan.org/r/51cce0fb-27ac-4fff-b9d4-214878850e54 (notice also there's no duplication of 'a'|'b' and User anymore)
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.