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

array key type not being checked for validity #3753

Closed
Almamu opened this issue Aug 19, 2020 · 11 comments
Closed

array key type not being checked for validity #3753

Almamu opened this issue Aug 19, 2020 · 11 comments

Comments

@Almamu
Copy link

Almamu commented Aug 19, 2020

Bug report

Array keys in typehints are not being checked for validity

Code snippet that reproduces the problem

https://phpstan.org/r/465607c6-3434-4b3f-bfbe-9add36193243

Expected output

I expected PHPStan to complain about the array key not being integer or string, in fact other tools (like phpdocumentor) do complain about it

@ondrejmirtes
Copy link
Member

This is expected behaviour. See #3269 for more details.

@Almamu
Copy link
Author

Almamu commented Aug 19, 2020

Shouldn't PHPstan complain about illegal types regardless of using @var or @param? As far as I understand, mixed and/or objects are not a valid key-type for any array as PHP only accepts integers or strings as keys but phpstan doesn't complain about it anywhere, maybe these examples are better suited to illustrate my point:
https://phpstan.org/r/65332cad-92e2-4cd4-b9ae-bde430adb827
https://3v4l.org/tWMsP

I expected it to complain like when you use an invalid typehint (for example a class that doesn't exist or incompatible types on inheritance):
https://phpstan.org/r/96e27f27-9077-485f-999c-3549d10e93c9
https://phpstan.org/r/f25b78fd-5d6e-4b5a-a22d-10ed62d1e3f3

@ondrejmirtes
Copy link
Member

Please read the linked issue. Here are the main takeaways:

  • local inline @var isn't for enforcing a variable type, just or telling PHPStan what's in the variable at the given moment
  • Types are enforced when put in @var above property or as @param/@return above functions and methods.

So you should enforce the array type when passing arrays into another property or function/method, or when returning from the current function/method, PHPStan otherwise currently doesn't support enforcing types of local variables.

@Almamu
Copy link
Author

Almamu commented Aug 19, 2020

I'm not talking about enforcing the type of a variable. The issue I'm talking about is the usage of ilegal types. Take this example:

<?php declare (strict_types=1);

/**
 * @param InexistentClass|null $var
 */
function example (?InexistentClass $var): void { var_dump ($var); }

/** @var InexistentClass|null */
$test = null;

phpstan will (rightfully) complain about both docblocks because the type InexistentClass is invalid (in this case it doesn't exist). Now look at this example:

<?php declare (strict_types=1);

/**
 * @param array<float, mixed> $var
 */
function example (array $var): void { var_dump ($var); }

/** @var array<float, mixed> */
$test = array (0.5 => 'test');

example ($test);

This one passes all the phpstan checks on level 8 (even with the strict rules in use), yet the type array<float, mixed> is ilegal according to the php documentation. Floats cannot be array keys. The example will run without issue on PHP (because there's an implicit conversion to integer going on according to the documentation) but will not yield the "expected" result and there is no indication from phpstan that this snippet is problematic at all.

@ondrejmirtes
Copy link
Member

Oh, I get what you’re complaining about now 😊

@ondrejmirtes ondrejmirtes reopened this Aug 19, 2020
@leongersen
Copy link
Contributor

@ondrejmirtes Would it be appropriate to check for this in InvalidKeyInArrayItemRule?

@ondrejmirtes
Copy link
Member

ondrejmirtes commented Aug 20, 2020

@leongersen Nope, that's a wrong place, that rule checks literal arrays in code.

In order to implement this, we need to TypeCombinator::intersect() the key here with new UnionType([new IntegerType(), new StringType()]), and also implement recursive checking for ErrorType/NeverType using TypeTraverser in this rule and others.

@leongersen
Copy link
Contributor

@ondrejmirtes Maybe I misunderstand, but TypeCombinator::intersect() for string|float and string|int would yield string, while string|float is an invalid array key type, right?

@ondrejmirtes
Copy link
Member

@leongersen Good observation. This is fine and it's already how PHPStan works. If you have something in your PHPDoc that gets normalized (like mixed&string -> string), no error message is reported, it's just done silently. Doing that on top of this feature request would be... another separate feature request :)

@ondrejmirtes
Copy link
Member

Implemented: phpstan/phpstan-src@1de5de8

@github-actions
Copy link

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 Jul 10, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants