Skip to content

array_column should not extract non-public properties from objects#5210

Open
janedbal wants to merge 1 commit intophpstan:2.1.xfrom
janedbal:array-column-visibility
Open

array_column should not extract non-public properties from objects#5210
janedbal wants to merge 1 commit intophpstan:2.1.xfrom
janedbal:array-column-visibility

Conversation

@janedbal
Copy link
Contributor

PHP's array_column respects calling scope visibility. This change:
- Checks scope->canReadProperty() before including a property type
- When both __isset and __get are defined, treats inaccessible
  properties as maybe-accessible (returns generic array)
- Handles NeverType in index position by falling back to integer keys

Fixes phpstan/phpstan#13573
@janedbal janedbal force-pushed the array-column-visibility branch from f8df7cc to 4252b95 Compare March 12, 2026 13:03
@janedbal janedbal marked this pull request as ready for review March 12, 2026 14:38
@phpstan-bot
Copy link
Collaborator

This pull request has been marked as ready for review.

@staabm staabm requested a review from VincentLanglet March 12, 2026 14:42
Comment on lines +255 to +256
assertType('array{}', array_column($objects, 'prot'));
assertType('array{}', array_column($objects, 'priv'));
Copy link
Contributor

Choose a reason for hiding this comment

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

This is not true with

class ParentObj extends ObjectWithVisibility {
    public int $prot = 2;
	public int $priv = 3;
}

Or even

class ParentObj extends ObjectWithVisibility {
	public string $priv = 'foo';
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What do you suggest? Only infer for final classes?

Copy link
Contributor

Choose a reason for hiding this comment

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

I would expect something like

assertType('list<int>', array_column($nonFinalObjects, 'pub'));
assertType('list<int>', array_column($finalObjects, 'pub'));

assertType('list<int>', array_column($nonFinalObjects, 'prot')); // Since the child need to respect the type.
assertType('array{}', array_column($finalObjects, 'prot'));

assertType('list<mixed>', array_column($nonFinalObjects, 'priv'));
assertType('array{}', array_column($finalObjects, 'priv'));
``

Copy link
Contributor

@staabm staabm Mar 16, 2026

Choose a reason for hiding this comment

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

just came to mind.. it can be also made a difference between

	/** @param array<int, ObjectWithVisibility> $objects */
	public function testNonPublicProperties(array $objects): void
	{

and implicit final

	public function testNonPublicProperties(): void
	{
		$objects = [new ObjectWithVisibility()];

@janedbal janedbal force-pushed the array-column-visibility branch from ae0ace2 to 4252b95 Compare March 16, 2026 13:30
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.

4 participants