-
-
Notifications
You must be signed in to change notification settings - Fork 864
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
Conditional return via static lookup array #9704
Comments
This gets you close: https://phpstan.org/r/ba879058-ecef-459c-b7ff-69e03be2ac1f The problem is that in the array you have class-strings but you want objects. I'm not sure if it can currently be solved, most likely we'd need some kind of type that lets us go from |
Thanks, that already looks better. Couldn't we use |
@ruudk After the latest push in 1.11.x, PHPStan now reports different result with your code snippet: @@ @@
15: PHPDoc tag @return with type array<string, string> is incompatible with native type object|null.
17: Dumped type: T of 'bar'|'foo' (method HelloWorld::get(), argument)
+18: Offset T of 'bar'|'foo' on array{foo: 'DateTime', bar: 'DateTimeImmutable'} on left side of ?? always exists and is not nullable.
+19: Strict comparison using === between 'DateTime'|'DateTimeImmutable' and null will always evaluate to false.
27: Dumped type: object|null
30: Dumped type: object|null Full report
|
It's getting better but still not working properly: https://phpstan.org/r/e9ae422d-ab7f-400e-99df-f213c1022b09 |
This patch would create an |
Thanks! @ondrejmirtes is this something you would accept as a PR? @rvanvelzen would you want to submit this as a PR? If you don't want to I can do it with your code. But you did the work obviously 😄 |
Maybe I'm having some kind of friday afternoon brain fart but what's the difference between |
The issue is that T is class-string, not an object of T. Introducing object would allow to type that. |
What about |
That's even better! |
Good news is: we can do it because a class cannot be named new: https://3v4l.org/YhCv3 |
@ruudk After the latest push in 1.11.x, PHPStan now reports different result with your code snippet: @@ @@
-15: PHPDoc tag @return with type array<string, string> is incompatible with native type object|null.
+15: PHPDoc tag @return with type array{foo: 'DateTime', bar: 'DateTimeImmutable'}[T] is incompatible with native type object|null.
17: Dumped type: T of 'bar'|'foo' (method HelloWorld::get(), argument)
+18: Offset T of 'bar'|'foo' on array{foo: 'DateTime', bar: 'DateTimeImmutable'} on left side of ?? always exists and is not nullable.
+19: Strict comparison using === between 'DateTime'|'DateTimeImmutable' and null will always evaluate to false.
27: Dumped type: object|null
30: Dumped type: object|null Full report
|
@ruudk After the latest push in 1.11.x, PHPStan now reports different result with your code snippet: @@ @@
-18: PHPDoc tag @return with type array<string, string> is incompatible with native type object|null.
+18: PHPDoc tag @return with type array{foo: 'DateTime', bar: 'DateTimeImmutable'}[T] is incompatible with native type object|null.
20: Dumped type: T of 'bar'|'foo' (method HelloWorld::get(), argument)
22: Dumped type: 'DateTime'|'DateTimeImmutable'
28: Dumped type: object|null
31: Dumped type: object|null Full report
|
This makes it possible that a new instance of a class-string will be returned. For example: ```php /** * @template T of class-string * @param T $type * * @return new<T> */ public static function get(string $type) : ?object { return new $type; } ``` Or a more complex example: ```php /** * @var array<string, class-string> */ private const TYPES = [ 'foo' => DateTime::class, 'bar' => DateTimeImmutable::class, ]; /** * @template T of key-of<self::TYPES> * @param T $type * * @return new<self::TYPES[T]> */ public static function get(string $type) : ?object { $class = self::TYPES[$type]; return new $class('now'); } ``` See phpstan/phpstan#9704 The work was done by @rvanvelzen in a gist. I just created the PR for it. Co-Authored-By: Richard van Velzen <rvanvelzen1@gmail.com>
This makes it possible that a new instance of a class-string will be returned. ```php /** * @var array<string, class-string> */ private const TYPES = [ 'foo' => DateTime::class, 'bar' => DateTimeImmutable::class, ]; /** * @template T of key-of<self::TYPES> * @param T $type * * @return new<self::TYPES[T]> */ public static function get(string $type) : ?object { $class = self::TYPES[$type]; return new $class('now'); } ``` See phpstan/phpstan#9704 The work was done by @rvanvelzen in a gist. I just created the PR for it. Co-Authored-By: Richard van Velzen <rvanvelzen1@gmail.com>
This makes it possible that a new instance of a class-string will be returned. ```php /** * @var array<string, class-string> */ private const TYPES = [ 'foo' => DateTime::class, 'bar' => DateTimeImmutable::class, ]; /** * @template T of key-of<self::TYPES> * @param T $type * * @return new<self::TYPES[T]> */ public static function get(string $type) : ?object { $class = self::TYPES[$type]; return new $class('now'); } ``` See phpstan/phpstan#9704 The work was done by @rvanvelzen in a gist. I just created the PR for it. Co-Authored-By: Richard van Velzen <rvanvelzen1@gmail.com>
Fixed phpstan/phpstan-src#3050 |
Bug report
I'm trying to let PHPStan understand the following code using a static
TYPES
array to lookup a given type.But whatever I try, it seems I cannot tell PHPStan that the return type will be an instance of the value from the
self::TYPES
constant array.I also tried:
Code snippet that reproduces the problem
https://phpstan.org/r/e086655c-9d6d-4ed8-9f80-c3e3f33bdc9b
Expected output
I expect it to correctly understand the type.
Did PHPStan help you today? Did it make you happy in any way?
It does, ❤️ PHPStan
The text was updated successfully, but these errors were encountered: