Hi
Am 2026-05-10 21:02, schrieb Seifeddine Gmati:
- RFC: https://wiki.php.net/rfc/bound_erased_generic_types
- Implementation: https://github.com/php/php-src/pull/21969
I haven't yet read the RFC itself in-depth. I generally agree with
Rowan's points that PHP users expect the runtime to enforce types for
them. With regard to the argument that “SA-checked” code could do
without runtime type checks for performance, I would like to note some
things that I have not seen mentioned (but I might have missed it in the
depths of the discussion):
Static analyzers can only prove the presence of errors, but not the
absence of them. It is impossible to fully and accurately type check a
PHP program without also executing it: The most obvious example would be
`unserialize()` which can materialize arbitrary objects based on
arbitrary inputs. `unserialize()` returns `mixed` for that reason.
PHPStan only checks usage of `mixed` starting at level 9. Guess what
level is being used by Symfony and Laravel respectively?
If one would actually use the highest possible level of the static
analysis tools they would need to “convince” the static analyzer that
“yes, unserialize() is actually returning an object of the right type”.
This is typically done with `assert($foo instanceof SomeClass);`,
something that PHP will double-check for you at runtime. My
understanding based on the discussion is that the RFC specifically
excludes support for `instanceof SomeClass<SomeType>`, folks would need
to fall back to `/** @var … */` comments or mark the offending line as
ignored in some other way - which basically means that even *if* PHP
supported generic syntax, they would need those doc comments. And the
same is true for any “extra types” supported by static analyzers that
are not supported by PHP itself, `non-empty-string`, `class-string`,
integer ranges or similar.
In an attempt to avoid as many false-negatives possible, static analysis
tools are also rejecting perfectly valid - and reasonable - PHP code due
to type mismatches. PHP allows to pass values of an “incorrect” type
when they can be loss-lessly represented as the target type - and then
guarantees that the stored value is of the correct type. This is
particularly useful when going from int -> string. This perfectly valid
PHP script is rejected by PHPStan with “Parameter #1 $x of function foo
expects string, int given”.
<?php
function foo(string $x): void { echo $x; }
foo(123);
But at the same time this PHP script is accepted by PHPStan despite
throwing “Uncaught TypeError: foo(): Argument #1 ($bar) must be of type
string, int given” at runtime:
<?php declare(strict_types = 1);
function foo(string $bar): void { }
foreach ($_GET as $key => $val) foo($key);
Gina has probably more to say about `strict_types=1` actually being
*less* safe than the default of using coercion (you'll probably find
emails in the list archives).
So depending on the configuration the existing - third party - static
analysis tools are accepting programs written in a custom programming
language that happens to share similarities with PHP such that it is
understood by the Zend Engine, but differs from PHP in relevant aspects,
being neither a subset, nor a superset of PHP.
Best regards
Tim Düsterhus