Skip to content

feat: resolve phpdoc array shapes to object schemas#2027

Merged
DerManoMann merged 1 commit into
zircote:masterfrom
alleknalle:feature-array-shapes
Jun 29, 2026
Merged

feat: resolve phpdoc array shapes to object schemas#2027
DerManoMann merged 1 commit into
zircote:masterfrom
alleknalle:feature-array-shapes

Conversation

@alleknalle

@alleknalle alleknalle commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Resolve array{...} to object schemas (properties/required) instead of collapsing them to a homogeneous map.

Summary

ArrayShapeType extends CollectionType, so array{...} phpdoc shapes fell into the
generic collection branch and were collapsed to a homogeneous map, losing member names
and required-ness. TypeInfoTypeResolver now resolves them to object schemas:

  • named-key shape → object with properties; non-optional keys → required
  • positional shape (array{0: T, 1: U}) → array with merged items
  • unsealed shape (array{a: int, ...}) → additionalProperties from the extra-value type
  • empty array{} → unchanged (falls through to existing collection handling)

Members resolve recursively (object members → $ref, nested shapes, nullable/union members).
Matched before CollectionType, so other collection handling is untouched.

Type of Change

New feature (non-breaking change that adds functionality)

Test Plan

Added cases to tests/Type/TypeResolverTest (3.0 and 3.1) via new DocblockAndTypehintTypes
fixture properties: scalar/optional/typed-open/untyped-open/positional/object-member/nested/
nullable-member/empty shapes. LegacyTypeResolver output left unchanged. Ran composer test
and composer analyse locally — all green.

  • Unit tests added/updated
  • Integration tests added/updated

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have commented my code where necessary
  • I have updated the documentation accordingly
  • My changes generate no new warnings
  • New and existing tests pass locally
  • Any dependent changes have been merged and published

@alleknalle alleknalle force-pushed the feature-array-shapes branch 2 times, most recently from d7d44c5 to 7a659c2 Compare June 23, 2026 22:12
Comment thread src/Type/TypeInfoTypeResolver.php Outdated
$shape = $type->getShape();

// A purely integer-keyed shape (array{0: T, 1: U}) is a positional list, not a keyed object.
if ($this->arrayShapeIsPositional($shape)) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Could this use array_is_list?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

@alleknalle alleknalle force-pushed the feature-array-shapes branch from 7a659c2 to b15befd Compare June 28, 2026 20:53

@DerManoMann DerManoMann left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Just the comment fix-up, then good to go. Sorry about the small iterations.

Comment thread src/Type/TypeInfoTypeResolver.php Outdated
Comment on lines +224 to +226
// An unsealed shape (array{a: int, ...} or array{a: int, ...<T>}) permits extra entries, so allow additional properties.
// The rest value type (...<T>) is left open because symfony/type-info resolves it inconsistently across versions (string vs int|string vs unresolved for the same ...<string>), so emitting it would be unstable and sometimes invalid.
// ArrayShapeType::isSealed() is defined as a null extra value type, so a non-null one means the shape is open.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

could this comment be put into a multiline /* ... */ comment with more line breaks?

Resolve array{...} to object schemas (properties/required) instead of collapsing them to a homogeneous map.
@alleknalle alleknalle force-pushed the feature-array-shapes branch from b15befd to 97b25e4 Compare June 29, 2026 07:54
@alleknalle alleknalle requested a review from DerManoMann June 29, 2026 07:54
@DerManoMann DerManoMann merged commit a5dddfe into zircote:master Jun 29, 2026
17 checks passed
@DerManoMann

Copy link
Copy Markdown
Collaborator

thanks @alleknalle

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.

2 participants