Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

/** @return static */ doesn't work properly with extended abstract class #4396

Closed
melya opened this issue Jan 19, 2021 · 17 comments
Closed

/** @return static */ doesn't work properly with extended abstract class #4396

melya opened this issue Jan 19, 2021 · 17 comments
Labels
Milestone

Comments

@melya
Copy link

melya commented Jan 19, 2021

Bug report

PHP Version: 7.4

Somehow /** @return static */ doesn't work properly in provided code snippet with extra abstract class.
However it works in simpler use-case like https://phpstan.org/r/18000821-8803-43f6-b17b-abd1d49c6cce

Code snippet that reproduces the problem

https://phpstan.org/r/771ab3d4-54fb-4552-8c4e-9ac0633e457c

<?php

declare(strict_types=1);

abstract class ClassC
{
    private string $value;
    
    private function __construct(string $value)
    {
        $this->value = $value;
    }
    
    /** @return static */
    public static function fromString(string $value): self
    {
        return new static($value);
    }
}

final class ClassB extends ClassC
{
}

final class ClassA
{
    public function classB(): ClassB
    {
        return ClassB::fromString("any");
    }
}

Expected output

ClassB::fromString("any") should not generate an error "Unsafe usage of new static()."

@ondrejmirtes
Copy link
Member

If you run this example locally you get:

Screenshot 2021-01-20 at 9 03 36

And the linked blogpost explains why you see this error and what you should do: https://phpstan.org/blog/solving-phpstan-error-unsafe-usage-of-new-static

@melya
Copy link
Author

melya commented Jan 20, 2021

Agree.
Sorry, I've prepared not a full example of my use-case.
Below is the correct one.

Please, take a look if that is the bug or we should always define return static in such cases ?
https://phpstan.org/r/fc9004dd-20d2-4ecb-a3e2-7cb9b59161f5

<?php

declare(strict_types=1);

interface TheInterface
{
	/** @return static */
	public static function fromString(string $value);
}

abstract class ClassC implements TheInterface
{
    private string $value;
    
    final private function __construct(string $value)
    {
        $this->value = $value;
    }
    
    // HERE: not defined "@return static" annotation leads to an error. 
    final public static function fromString(string $value): self
    {
        return new static($value);
    }
}

final class ClassB extends ClassC
{
}

final class ClassA
{
    public function classB(): ClassB
    {
        return ClassB::fromString("any");
    }
}

@ondrejmirtes ondrejmirtes reopened this Jan 20, 2021
@ondrejmirtes
Copy link
Member

Yeah, the implicit PHPDoc inheritance should probably work in this case. Until it's fixed, please use the explicit /** @return static */ in ClassC as well.

@ondrejmirtes ondrejmirtes added this to the Easy fixes milestone Jan 20, 2021
@mvorisek
Copy link
Contributor

I belive this should be closed - when : self is defined, phpstan error is correct as another class of extending abstract class can be returned

@phpstan-bot
Copy link
Contributor

@melya After the latest commit in dev-master, PHPStan now reports different result with your code snippet:

@@ @@
-No errors
+7: Property ClassB::$value is never read, only written.
Full report
Line Error
7 Property ClassB::$value is never read, only written.

@phpstan-bot
Copy link
Contributor

@melya After the latest commit in dev-master, PHPStan now reports different result with your code snippet:

@@ @@
+ 7: Property ClassC::$value is never read, only written.
 17: Unsafe usage of new static().
Full report
Line Error
7 Property ClassC::$value is never read, only written.
17 Unsafe usage of new static().

@phpstan-bot
Copy link
Contributor

@melya After the latest commit in dev-master, PHPStan now reports different result with your code snippet:

@@ @@
+13: Property ClassC::$value is never read, only written.
 34: Method ClassA::classB() should return ClassB but returns ClassC.
Full report
Line Error
13 Property ClassC::$value is never read, only written.
34 Method ClassA::classB() should return ClassB but returns ClassC.

@phpstan-bot
Copy link
Contributor

@melya After the latest commit in dev-master, PHPStan now reports different result with your code snippet:

@@ @@
-No errors
+7: Property ClassB::$value is never read, only written.
Full report
Line Error
7 Property ClassB::$value is never read, only written.

@phpstan-bot
Copy link
Contributor

@melya After the latest commit in dev-master, PHPStan now reports different result with your code snippet:

@@ @@
+ 7: Property ClassC::$value is never read, only written.
 17: Unsafe usage of new static().
Full report
Line Error
7 Property ClassC::$value is never read, only written.
17 Unsafe usage of new static().

@phpstan-bot
Copy link
Contributor

@melya After the latest commit in dev-master, PHPStan now reports different result with your code snippet:

@@ @@
+13: Property ClassC::$value is never read, only written.
 34: Method ClassA::classB() should return ClassB but returns ClassC.
Full report
Line Error
13 Property ClassC::$value is never read, only written.
34 Method ClassA::classB() should return ClassB but returns ClassC.

@phpstan-bot
Copy link
Contributor

@melya After the latest commit in dev-master, PHPStan now reports different result with your code snippet:

@@ @@
-17: Unsafe usage of new static().
+17: Unsafe usage of new static().
+ 7: Property ClassC::$value is never read, only written.
Full report
Line Error
17 Unsafe usage of new static().
7 Property ClassC::$value is never read, only written.

@phpstan-bot
Copy link
Contributor

@melya After the latest commit in 1.8.x, PHPStan now reports different result with your code snippet:

@@ @@
+PHP 8.0 (3 errors)
+==========
+
+13: Property ClassC::$value is never read, only written.
+15: Private method ClassC::__construct() cannot be final as it is never overridden by other classes.
+34: Method ClassA::classB() should return ClassB but returns ClassC.
+
+PHP 7.1 – 7.4 (2 errors)
+==========
+
+13: Property ClassC::$value is never read, only written.
 34: Method ClassA::classB() should return ClassB but returns ClassC.
Full report

PHP 8.0 (3 errors)

Line Error
13 Property ClassC::$value is never read, only written.
15 Private method ClassC::__construct() cannot be final as it is never overridden by other classes.
34 Method ClassA::classB() should return ClassB but returns ClassC.

PHP 7.1 – 7.4 (2 errors)

Line Error
13 Property ClassC::$value is never read, only written.
34 Method ClassA::classB() should return ClassB but returns ClassC.

@luxemate
Copy link

luxemate commented Apr 6, 2023

@ondrejmirtes I'm not sure if it's related or should I create another issue, but static type hint also works strange with final classes.

<?php declare(strict_types = 1);

class HelloWorld
{
	/** @return static */
	public function sayHello(): self
	{
		return new self();
	}
}

https://phpstan.org/r/a6e4516b-4a9b-4d60-83d5-6392aad8f8cd Here without final it shows an error Method HelloWorld::sayHello() should return static(HelloWorld) but returns HelloWorld..

https://phpstan.org/r/c3800156-3cbd-4817-83db-4a9b1dcd3d01 But here with final it's all fine, although return types differ and final + static makes little sense.

@ondrejmirtes
Copy link
Member

@luxemate Please do not hijack unrelated bug reports with your own issue. Open a discussion instead, thanks.

@luxemate
Copy link

luxemate commented Apr 6, 2023

@ondrejmirtes No problem. I just thought it is related because it pretty much looks so. :)

@ondrejmirtes
Copy link
Member

Fixed: phpstan/phpstan-src#2803

Copy link

github-actions bot commented Jan 9, 2024

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 github-actions bot locked as resolved and limited conversation to collaborators Jan 9, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

5 participants