phpstan icon indicating copy to clipboard operation
phpstan copied to clipboard

Not throwing Method ... overrides method ... but misses parameter when compatible with an interface but not parent.

Open jlekowski opened this issue 2 years ago • 2 comments

Bug report

An overridden method signature different than in a parent class is considered correct even though PHP throw Fatal error.

I believe the issue comes from the fact that the method is compared to its prototype https://github.com/phpstan/phpstan-src/blob/1.8.x/src/Rules/Methods/MethodParameterComparisonHelper.php#L35 and the prototype is taken from here https://github.com/ondrejmirtes/BetterReflection/blob/5.8.x/src/Reflection/ReflectionMethod.php#L171, which is looking for an interface instead of the immediate parent method.

Code snippet that reproduces the problem

<?php declare(strict_types = 1);

interface A
{
	public function test(): void;
}

class B implements A
{
	public function test(mixed $a = null): void
	{
	}
}

class C extends B
{
	public function test(): void
	{
	}
}

or links below: https://phpstan.org/r/dafd527b-bf9f-484d-b660-237ef64309a7 - the error is marked for ExtendingClassNotImplementingSomeInterface class only and ExtendingClassImplementingSomeInterface is considered to be correct. An example where PHP throws the following error https://3v4l.org/1PYEd#v8.1.9

Fatal error: Declaration of ExtendingClassImplementingSomeInterface::getList(mixed $a): void must be compatible with ImplementingSomeInterface::getList(mixed $a, bool $b = false): void in /in/1PYEd on line 19

Expected output

Method ExtendingClassImplementingSomeInterface::getList() overrides method ImplementingSomeInterface::getList() but misses parameter #2 $b.

Did PHPStan help you today? Did it make you happy in any way?

I run it before each commit :)

jlekowski avatar Aug 25 '22 16:08 jlekowski

Maybe the same as https://github.com/phpstan/phpstan/issues/7388?

canvural avatar Aug 25 '22 19:08 canvural

@canvural, it is very similar, thanks for the reference. I'm not sure if the bug you reported is caused by the same logic. In my case, I can see it is the method's prototype being taken from the (parent's) interface and the immediate parent method is ignored.

jlekowski avatar Aug 26 '22 09:08 jlekowski

@jlekowski After the latest push in 1.11.x, PHPStan now reports different result with your code snippet:

@@ @@
+19: Method ExtendingClassImplementingSomeInterface::getList() overrides method ImplementingSomeInterface::getList() but misses parameter #2 $b.
 35: Method ExtendingClassNotImplementingSomeInterface::getList() overrides method NotImplementingSomeInterface::getList() but misses parameter #2 $b.
Full report
Line Error
19 Method ExtendingClassImplementingSomeInterface::getList() overrides method ImplementingSomeInterface::getList() but misses parameter #2 $b.
35 Method ExtendingClassNotImplementingSomeInterface::getList() overrides method NotImplementingSomeInterface::getList() but misses parameter #2 $b.

phpstan-bot avatar Nov 08 '23 22:11 phpstan-bot

Thanks @ondrejmirtes :+1:

jlekowski avatar Nov 09 '23 12:11 jlekowski

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.

github-actions[bot] avatar Dec 11 '23 00:12 github-actions[bot]