In my code, I call a method whose return value is typed as follows:
/**
* @return array<int, array<string,mixed>>
*/
public function fetchAllAssociative(): array;
The subtype array<string, mixed> describes the database record in a generic way. I know exactly what this database record looks like so I want to be more specific in documenting the method:
/**
* @return array<int, array{id: int, firstName: string, lastName: string}>
*/
public function getAllUsers(): array
{
return $this->userRepository->fetchAllAssociative();
}
However, PHPStan complains that I should type my methods exactly as fetchAllAssociative:
Method UserRepository::getAllUsers() should return array<int, array{id: int, firstName: string, lastName: string}> but returns array<int, array<string, mixed>>.
Is there a way to cast it? My workaround is to introduce a new variable and use the @var tag but I don't really like it (other static code analysis tools don't like it as well)
/**
* @return array<int, array{id: int, firstName: string, lastName: string}>
*/
public function getAllUsers(): array
{
/**
* @var array<int, array{id: int, firstName: string, lastName: string}> $data
*/
$data = $this->userRepository->fetchAllAssociative();
return $data;
}
I ran into something similar. Unfortunately, I think adding
// @phpstan-ignore-next-lineto the implementation is the only other thing you can do.In Typescript, this is basically equivalent to asserting that
anyisUser. Typically this would happen in a "makeUser" function the moment you get and validate the data (e.g. from a database or an http request) so that you can minimize yourdata as unknown as Userusages. Otherwise, this is the consequence.So, general advise to anyone else running into this, start with your repositories and really make it a point to avoid
array<mixed>andmixed, cause it's going to quickly trickle throughout your system.