Re: [RFC] [Discussion] Literal Scalar Types
| From: | Tim Düsterhus | Date: | Mon, 15 Jun 2026 18:55:23 +0000 |
| Subject: | Re: [RFC] [Discussion] Literal Scalar Types | ||
| References: | 1 2 3 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-131294@lists.php.net to get a copy of this message | ||
Hi
On 6/15/26 04:12, Seifeddine Gmati wrote:
1. describing APIs that already exist.We can retype this kind of API with enums. See the “Correctly name the rounding mode and make it an Enum” RFC (https://wiki.php.net/rfc/correctly_name_the_rounding_mode_and_make_it_an_enum) for an example: We first widen the parameter to accept the enum so that folks can opt-in to the new API. At a later point we alias the constants to the corresponding enum cases and deprecate passing the integers and then we remove the support for the integers (and constants). Using literal types is going to result in a terrible user-experience, because the signature does not provide any hint as to which constants are supposed to be used with the API which means that the resulting error message is also useless to the user. Enums - or the existing manual validation - is much preferable here.array_filter's$modereally accepts0|1|2, but it's typedintbecause that's all the type system can say today. we can't retype it as an enum without breaking every caller. a literal union lets the signature state the actual contract.
2. ad-hoc / open value sets. for a library, "ascii"|"utf-8" would need
its own named symbol ( enum BorderStyle { case Ascii; case Utf8 }, a
new file, an import ) for what is really two strings. and because an
enum is a closed set, adding a third style later breaks any consumer
that match-es over it without a default. widening the union on a
parameter ( "ascii"|"utf-8"|"unicode" ) is contravariant, so it breaks
nobody.
The existing \RoundingMode enum is already intended to be a non-exhaustive (parameter-only) enum where users are expected to include a default case in case new values are being added.
I have a *very* rough draft in https://wiki.php.net/rfc/non_exhaustive_marker to make this type of contract more explicit.
Having an “own named symbol” for the allowed values is a benefit to me, because this makes it easy to reuse the list of allowed values in different locations without needing to resort to copy and paste, for example in decorators that just pass through the values without touching them.
3. scalar interop. a literal value is the scalar, so it works as an array key, compares with ===, round-trips through json, etc. enum cases are objects and don't.Enums can be compared with
===.
Best regards
Tim Düsterhus