> - RFC: https://wiki.php.net/rfc/bound_erased_generic_types
> - Implementation: https://github.com/php/php-src/pull/21969

Hello Internals,

Status update: RFC is now at v0.22.

Two changes are worth flagging.

1. Substituted runtime contracts are now enforced end-to-end on
inherited members.

A child class binding a generic parent now enforces the substituted
parameter and return types at runtime at every site the substitution
touches: method and constructor entry (including defaults and
per-element variadics), return values, backed property storage,
property hook get/set signatures, and trait-imported method and
property types. Enforcement is uniform regardless of the parent's
bound, a child binding T to int on Box<T : mixed> rejects non-int
values everywhere, not just where the parent's bound happened to be
stricter.

This collapses the "body bytecode is not recompiled per substitution"
caveat from earlier drafts. The specific case the previous Limitations
text called out as observable (a virtual hook returning a hardcoded
value of the wrong substituted type) now throws an error. The
Limitations section is down to three bullets: type-argument erasure
(Box<int> accepts a Box<string> because the runtime check is
instanceof Box), turbofish doesn't tighten parameters, and
method-level T-bound resolves to the bound rather than the
per-instance instantiation.

2. Reflection: plural ancestor-binding getter.

`ReflectionClass::getGenericArgumentsForParentInterface()` now returns
`list<list<ReflectionType>>`. A class binding the same generic
interface multiple times, gets every binding as a separate outer-list
entry. The previous singular shape silently dropped all but one. (
e.g. `class Bar implements Foo<int>, Foo<string>`)

Cheers,
Seifeddine.

Reply via email to