On 15 May 2026 00:32:05 BST, Seifeddine Gmati <[email protected]> wrote:
>Generic type information currently lives in optional levels because it
>lives in optional syntax (docblocks).
This is, quite frankly, nonsense.
If you write a function with no native type information, but an "@return int"
docblock, PHPStan will report an error for a missing return statement at Level
0, and for an incorrect return statement on Level 3.
There's no relationship between the syntax needed and the types of analysis
performed.
> That's the point: native syntax means the language
>did the work, and tools surface violations at whatever strictness the
>user already has configured.
As Daniil pointed out, SA tools analyse code with offline parsers, not by
loading and reflecting it; so the native enforcement of arity etc will still
need to be reimplemented in each tool.
The RFC will act as a standardisation of what tools *should* enforce around
those things; but that could equally be done by agreeing a set of conformance
tests based on the existing docblock syntax. In fact, those conformance tests
would be needed whatever the syntax, if the goal is to eliminate different
handling in different tools.
>The actual situation is that PHP has a runtime-checked layer (what the
>engine validates) and an SA-checked layer (what tools verify). The two
>layers complement each other. Native generics formalize a part of the
>SA-checked layer that the engine can partially absorb.
I can agree with this framing. I think where we differ is that you see unifying
those layers in one syntax as a good thing, but I see it as a bad thing: I
think it is useful to be able to look at the code, and understand which parts
are definitely going to be enforced by the runtime-checked layer.
I think the ideal is to somehow create a standardised syntax for the SA-checked
layer, but still keep it separate from the syntax for the runtime-checked
layer. If neither docblocks nor attributes are a good basis for that, maybe
there's some other primitive we can add so that users can mark both the
"runtime type" and the "SA type".
Straw man example:
class Foo ~~Foo<T> extends Bar ~~Bar<int,T> {
public function foo(string ~~non-empty-string $in): array ~~list<T> {
...
Maybe PHP would process the syntax, but not the semantics, of the extra type
information; SA tools would then be free to invent new pseudotypes within that
framework, without needing to wait for a full PHP release cycle every time.
Rowan Tommins
[IMSoP]