Skip to content

Conversation

@canvural
Copy link
Contributor

This PR adds return type extensions for array_first and array_last


public function isFunctionSupported(FunctionReflection $functionReflection): bool
{
return $functionReflection->getName() === 'array_first' && $functionReflection->isBuiltin();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is the correct way. Maybe we can check the PHP version. Because I thought there might be userland functions named array_first that would also be processed here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's okay like this, we don't check this anywhere for similar extensions. As a benefit it'd also work for polyfills running on lower PHP versions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So should I remove the $functionReflection->isBuiltin() part?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes 😊

use function count;

#[AutowiredService]
final class ArrayLastDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as this 2 extensions are very similar, you might consider using a single extension class for handling both

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the recent refactoring they are now merged into one


public function isFunctionSupported(FunctionReflection $functionReflection): bool
{
return $functionReflection->getName() === 'array_first' && $functionReflection->isBuiltin();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's okay like this, we don't check this anywhere for similar extensions. As a benefit it'd also work for polyfills running on lower PHP versions.

return new NullType();
}

$valueType = $argType->getFirstIterableValueType();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I thought about the implementation, I'd do only getIterableValueType. The getFirstIterable*Type methods are highly misleading and we should get rid of it. Because array shapes do not enforce the order of the keys. Sorry to put more burden on you, but can you please deprecate Type::getFirstIterableKeyType, getLastIterableKeyType, getFirstIterableValueType, getLastIterableValueType and use getIterableKeyType and getIterableValueType in all places instead? And just update any test assertions because of that. Thank you!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright. I can do that. But we will lose the precise type for constant arrays that way.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's okay. Ideally we would have two separate implementations for literal arrays and PHPDoc array shapes but we don't.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done with 73651b5 and 5f3237a

I didn't really check the assertions, just fixed whatever PHPStan said.

@ondrejmirtes
Copy link
Member

Awesome, looks like it fixed phpstan/phpstan#8270. Please add a regression test.

@canvural
Copy link
Contributor Author

Awesome, looks like it fixed phpstan/phpstan#8270. Please add a regression test.

I'm not sure what got fixed. For PHP 7.3 - 8.2 there are no errors already. And for < 7.3 it doesn't make sense because array_key_first doesn't exist there.

@staabm
Copy link
Contributor

staabm commented Oct 31, 2025

I'm not sure what got fixed

see https://github.com/phpstan/phpstan-src/actions/runs/18969820143

looks like it fixed the "If condition is always true." error

@canvural
Copy link
Contributor Author

But that is already not reported https://phpstan.org/r/b63fa8a0-6ca6-4ac4-a8ca-b0a76cb22494 🤔

@staabm
Copy link
Contributor

staabm commented Oct 31, 2025

I think it is: https://phpstan.org/r/84f65522-eace-4181-90c1-98c6a0f85206
(strict rules enabled)

@canvural
Copy link
Contributor Author

I don't understand it fully, but I did this 3530dd2 Though it still fails locally 🤷🏽

@ondrejmirtes
Copy link
Member

Probably not fixed then and we're just misinterpreting the results somehow 😊

@canvural
Copy link
Contributor Author

Reverted then.

@ondrejmirtes ondrejmirtes merged commit 46c2519 into phpstan:2.1.x Oct 31, 2025
1071 of 1107 checks passed
@ondrejmirtes
Copy link
Member

Thank you!

@canvural canvural deleted the array_first_last branch October 31, 2025 12:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants