Re: [RFC] [Discussion] Literal Scalar Types
| From: | Seifeddine Gmati | Date: | Mon, 15 Jun 2026 16:44:16 +0000 |
| Subject: | Re: [RFC] [Discussion] Literal Scalar Types | ||
| References: | 1 2 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-131285@lists.php.net to get a copy of this message | ||
Hi Jordi,
> Does the RFC allow referencing constants in type positions, or only raw
literal values?
>
> ```
> function foo(STATUS_ACTIVE|STATUS_INACTIVE $sort): void {}
> ```
Regarding your first point, referencing constants in type positions is not
supported. This RFC focuses specifically on scalar literals. A constant
access is not a literal itself, and allowing something like
FOO in a type
position could cause ambiguity; at first sight, it's unclear whether it
refers to a class name or a constant. While casing might suggest one or the
other to a human, PHP allows both classes and constants to use any casing
style, which could lead to confusion.
This would also be a BC break, as the following is currently permitted in
PHP:
```
const Foo = 1;
class Foo {}
function bar(Foo $hello): void {}
```
If Foo were changed to mean 1 instead of an instance of Foo
depending
on the surrounding context, this would break existing applications.
> ```
> What about enum values? For example:
>
> function bar(Status::Active->value $status): void {}
> // or simply as
> function bar(Status::Active $status): void {}
> ```
For the second point, using enum values is also out of scope.
Status::Active->value is a runtime expression, not a literal: the engine
would have to confirm that Status is an enum, that the case exists, and
that it is backed before reading ->value. And Status::Active by itself
is an object, a single enum case, which would be a single-case type, a
separate feature from scalar literals. In both situations, requiring the
enum type itself is usually the better fit.
> Also, I'm not really a fan of mixing literal types with unions.
>
> ```
> function foo(int|'bar' $param): void {}
> ```
Finally, regarding mixing literal types with wider types like int|'bar',
this is supported by design. I believe restricting what may appear in a
union is the wrong approach; PHP should treat types uniformly, with
exceptions only for types that aren't value types and so are meaningless in
a union (void, never) or that are redundant (mixed|T, or a
literal
already covered by its base type like int|1). If a union like
float|'cold'|'hot' lets a user express a real requirement for their
API,
the type system should allow it.
Cheers,
Seifeddine.