Skip to content

Help phpstan understand what shape array has been created when looping over an array with known shape #13000

@mind-bending-forks

Description

@mind-bending-forks

Feature request

Please accept my apologies if this has been requested before. It almost certainly has. I did search but I couldn't find a duplicate issue though. Also, please accept my apologies for failing to find the words describe my request concisely or even accurately. Here is what I actually mean:

https://phpstan.org/r/6e3e0f1e-dfb3-42e1-b562-e15f662c0f05

/**
 * @return array{'a':string,'b':string}
 */
function R() : array
{
	$r = [];
	foreach ( ['a' => '1', 'b' => '2'] as $key => $val )
	{
		$r[$key] = $val;
	}
	return $r;
}

In this case, phpstan knows what the shape of the array being iterated over is. It can know that $key will take value 'a' and value 'b', and so it can know that the returned array will have keys 'a' and 'b', and so will be compatible with the declared return type of the function. However, for some reason, it only knows that it has at least one key with value 'a' or 'b', and so reports:

Function R() should return array{a: string, b: string} but returns non-empty-array<'a'|'b', '1'|'2'>.

As a user of phpstan, if you want to adapt your code to educate it (which ought not be necessary in this case), it seems that you've got to list every key that you already know is present in the output array individually. Something like this:

https://phpstan.org/r/40b9069c-0362-497e-8893-af33763fbf19

That is not very convenient when the arrays are larger though. Trying to loop over keys is not going to help either, since phpstan's understanding of loops are the source of the issue:

https://phpstan.org/r/e4574f6d-24f4-438f-8adb-8281b65fc687

So, it seems that the only practical solution is to instruct phpstan to ignore its return.type error, which fortunately, I rarely have to do these days. Would be good if it wasn't necessary.

In case it helps, the situation where I encountered this was a bit more complex, but basically boiled down to reproducing a (nested, actually) array structure, but with transformed values. A simplified version would look something like this:

https://phpstan.org/r/9b67f7ec-2658-428e-b914-d86e47df6e38

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

Yes. Pay for Pro for that reason.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions