Skip to content

Make AbstractClassMetadataFactory an internal detail of Doctrine projects - #534

Open
mpdude wants to merge 4 commits into
doctrine:4.3.xfrom
mpdude:acmf-internal
Open

mpdude wants to merge 4 commits into
doctrine:4.3.xfrom
mpdude:acmf-internal

Conversation

@mpdude

@mpdude mpdude commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

This change intends to announce that nobody outside Doctrine projects should use the ACMF base class for extension or for type-hinting in their own code. It should be considered an internal implementation detail of Doctrine projects and may change or go away at any time without further notice (maybe after we reached the next major version?).

That also means Doctrine projects no longer need to use it as a base class for their more specific implementations.

This gives us more freedom to change ACMF implementations towards doctrine/orm#12203.

Empirical research done by a Claude agent reported that the provided annotations cover the use case for PHPStan, but leave a gap in Psalm that does not prevent type-hinting (only extension).

Details
Goal 2 — closed base, but shipped subclasses stay usable

Fully achievable in PHPStan, only half achievable in Psalm.
/**
 * @internal
 * @psalm-inheritors \Acme\Lib\LibConcreteSub
 */
abstract class LibAbstractBase { ... }
- PHPStan: extends blocked, and type-hinting the abstract base itself gets blocked (property.internalClass etc.), while the shipped LibConcreteSub stays completely free to type-hint. Needs both tags — @psalm-inheritors alone doesn't block type-hints; @internal alone happens to cover both in this case.
- Psalm: blocks extends fine, but there's no mechanism that discourages type-hinting the abstract base itself — tested three variants, all came back clean. That's a flat gap in Psalm, not a workaround-able one.

…ojects

This change intends to announce that nobody outside Doctrine projects should use the ACMF base class for extension or for type-hinting in their own code. It should be considered an internal implementation detail of Doctrine projects and may change or go away at any time without further notice (maybe after we reached the next major version?).

That also means Doctrine projects no longer need to use it as a base class for their more specific implementations.

This gives us more freedom to change ACMF implementations towards doctrine/orm#12203.

Empirical research done by a Claude agent reported that the provided annotations cover the use case for PHPStan, but leave a gap in Psalm that does not prevent type-hinting (only extension).

<details>
```
Goal 2 — closed base, but shipped subclasses stay usable

Fully achievable in PHPStan, only half achievable in Psalm.
/**
 * @internal
 * @psalm-inheritors \Acme\Lib\LibConcreteSub
 */
abstract class LibAbstractBase { ... }
- PHPStan: extends blocked, and type-hinting the abstract base itself gets blocked (property.internalClass etc.), while the shipped LibConcreteSub stays completely free to type-hint. Needs both tags — @psalm-inheritors alone doesn't block type-hints; @internal alone happens to cover both in this case.
- Psalm: blocks extends fine, but there's no mechanism that discourages type-hinting the abstract base itself — tested three variants, all came back clean. That's a flat gap in Psalm, not a workaround-able one.

```
</details>
greg0ire
greg0ire previously approved these changes Nov 7, 2026
@greg0ire
greg0ire requested a review from stof November 7, 2026 15:35
Comment thread phpstan-baseline.neon Resolved
Comment thread UPGRADE.md Resolved
@mpdude

mpdude commented Nov 8, 2026

Copy link
Copy Markdown
Contributor Author

Feedback addressed, thank you!

@mpdude
mpdude requested review from GromNaN and greg0ire November 9, 2026 09:40
Comment thread phpstan.neon Resolved
Co-authored-by: Christophe Coevoet <stof@notk.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants