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

Add a way to ignore/override a stub from an extension #10906

Open
VincentLanglet opened this issue Apr 18, 2024 · 7 comments
Open

Add a way to ignore/override a stub from an extension #10906

VincentLanglet opened this issue Apr 18, 2024 · 7 comments

Comments

@VincentLanglet
Copy link
Contributor

Feature request

When two stubs are declaring the same class we're ending with
Class Foo declared multiple times: which is not ignorable.

I see many use case

  • I have Library 1 which has a stub for the Foo class
  • I have Library 2 which also has a stub for the Foo class => Conflict
  • I have Library 1 which has a stub for the Foo class
  • I have a custom stub for the Foo class but the PR was not accepted on the library (or is pending) => Conflict

Notice both of this situation are easy to happen because when we're defining a stub, all the class need to be defined so we're often ending creating "empty stub" like https://github.com/phpstan/phpstan-symfony/blob/1.4.x/stubs/Symfony/Component/Console/Exception/ExceptionInterface.stub ; and two different lib can ending defining the same "empty stub" (or one of them might not be empty).

It should be useful to have something like a way to ignore/prefer a stub.

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

Yes, PHPStan is great.

@ondrejmirtes
Copy link
Member

This feature request sometimes come back around and is asked again, but I maintain the opinion that there should still be just a single stub for each symbol, and it should be correct. There shouldn't be a reason for two stub files of the same symbol to exist.

What we might be able to do is to merge two stubs of the same class if there's no overlap between the overriden methods, if there's no conflict essentially.

@VincentLanglet
Copy link
Contributor Author

This feature request sometimes come back around and is asked again, but I maintain the opinion that there should still be just a single stub for each symbol, and it should be correct. There shouldn't be a reason for two stub files of the same symbol to exist.

I agree that "it should", but IMHO, it's in a world where

  • every phpstan extensions has perfect stub
  • every phpdoc is perfect

If an extension is unmaintained and provide lot of useful stub but also an old stub, there is no easy way to exclude the stub for instance. Same might happen if someone sent a PR for a stub non wanted by every one (for instance people might be tired of literal-string issues or benevolent union or list<array> from doctrine)...

In the same way there is

services:
	exceptionTypeResolver:
		class: App\MyCustom\ExceptionTypeResolver

I would have find useful to have

services:
	stubFilesProvider:
		class: App\MyCustom\StubFileProvider

because the StubFilesExtension entry point allows to add new stubs but there is no way to filter out a stub.

@ondrejmirtes
Copy link
Member

I'm still not convinced :)

If an extension is unmaintained

Then you should fork it. Using unmaintained software is going to bring you problems sooner or later anyway.

people might be tired of literal-string issues

For that there's ignoring errors.

But as I said, merging mutliple class stubs with not-overlapping methods might be possible.

@VincentLanglet
Copy link
Contributor Author

people might be tired of literal-string issues

For that there's ignoring errors.

Stub sometimes provide a way to ignore all issue in one. I'll give you a personal (opinionated) example.
You reported here phpstan/phpstan-doctrine#453 (comment) that the dynamic return type extensions was returning list<array> (previously it was mixed) which was not precise enough and annoying because it reported some errors like

/** @return list<array{string, string, string}> */
public function foo(): array
{
    return $qb
            ->select('a.one, a.two, a.three')
            ->getQuery()
            ->getResult(AbstractQuery::HYDRATE_SCALAR);
}

"Error: foo should return list<array{string, string, string}> but returns list<array<mixed>> on level 7 when before it was on level 9.

In the same way the issue can occur with Result::fetchAllAssociative()

/** @return list<array{string, string, string}> */
public function foo(): array
{
    return $this->connection->executeQuery('Select a.one, a.two, a.three')->fetchAllAssociative();
}

because the phpdoc is list<array<mixed>> https://github.com/doctrine/dbal/blob/7fb00fdf7091a3ab0a4b6d0eed12170b4c7c2aa8/src/Result.php#L88 and a stub with @return mixed was an easy way to move the error from level 7 to level 9, rather than have to ignore a new error every time a new fetchAllAssociative was made.

But I clearly understand it's not how you want stub to be used... ^^'

@LastDragon-ru
Copy link

LastDragon-ru commented Apr 20, 2024

+1 for merging and overriding methods. One of the case the larastan - it is not 100% full, so sometimes it can be useful.

Another related edge case are extensions - there is no way disable unwanted :( See #10410 (I use custom helper to remove unwanted rules...)

@ondrejmirtes
Copy link
Member

Extensions can offer options to disable services, if it's a valid use-case (and not just a workaround to a larger issue). Look at phpstan-strict-rules config where everything can be turned off: https://github.com/phpstan/phpstan-strict-rules/blob/1.6.x/rules.neon

@LastDragon-ru
Copy link

Extensions can offer options to disable services

Yep, but usually they are not :(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants