Hi Nick,
Thanks for the feedback.
> 1) if I did not miss anything the empty string case is not covered.
> Would `""` be legal? Any thoughts on providing ways to explicitly
> disallow empty strings? I don't think this should be further scope --
> because we would need to make sure that we actually have a usable syntax
> to disallow empty strings.
Empty strings are supported; "" is a valid literal string type. Regarding
non-empty-string, that is a separate concept from literal types. However,
this RFC provides the building blocks to express it in the future, through
negated types (e.g., !""). There's also the option of doing refinement
markers on base types (e.g., string[1..]), which IIRC Gina is working on or
mentioned it somewhere.
Example ( using literal types, negated types, and type aliases ):
```php
type NonEmptyString = ! "";
function getNonEmptyString(): NonEmptyString {
return 'ok'; // ok
return ''; // err
}
```
> 2) having strict and non-strict mode in PHP is bad enough, IMO. Seeing
> this brought further, and combined with "literal" (literal should be
> literal) feels wrong -- a coerced `true` is de facto not a literal 1,
> it's a coerced `true`. I understand that you recommend strict and want
> to leave it to a vote, but I feel like the "Coercive matching
> (alternative)" section should make a stronger point against it, to
> discourage a tempting "always been like that" for a new concept.
The RFC highlights that strict matching is already the established behavior
for existing value-types in PHP, and is the preferred path. true, false,
and null never coerce, even in coercive mode. Maintaining this for all
literal types is the only way to ensure a consistent type system where a
unit type matches exactly its identity, hence it is the preferred option.
> 3) the performance section is thin; solely addressing what Tim brought
> up. I am wondering, does introducing this have any implications for
> non-literal types? Having a benchmark would be nice. I also agree with
> Jorg, that a benchmark comparing the performance with enums (memory +
> speed) would be helpful.
This proposal has no performance impact on non-literal type checks.
Comparing it to enums isn't quite apples-to-apples; enums are objects and
follow standard object comparison logic, whereas these are scalar identity
checks.
> 4) the last part of the previous point extends to the general usefulness
> of the feature. I again have to agree with Jorg: it is not clear what
> problem it is trying to solve. Why not enums? It is a trend to get rid
> of stringy APIs, and magic strings and ints -- for reasons. But this
> feature will encourage bringing them back. With an enum you define it in
> one place (easier to refactor), with literal scalar types you repeat it
> in multiple places. Do we really want that?
The core goal is to expand the type system to allow for more precise
descriptions of data. While literal types can be used standalone, they are
fundamental for future features like array shapes, where keys and values
often need to be narrowed to specific literals (e.g., a status key being
exactly 'ok' | 'error'). A richer type system, similar to what we see in
TypeScript, requires literals as a foundational building block.
Example ( using literal types, type aliases, array shapes, and integer
ranges ):
```php
type ActionResponse = ['status' => 'ok' | 'error', 'message' => string,
?'data' => array];
interface Action {
public function perform(Context $ctx, Request $request): ActionResponse;
}
type PingActionResponse = ['status' => 'ok', 'message' => 'pong', 'data' =>
['time' => 0..]];
final readonly class PingAction extends Action {
public function perform(Context $ctx, Request $request):
PingActionResponse {
return ['status' => 'ok', 'message' => 'pong', 'data' => ['time' =>
get_time()]];
}
}
```
Cheers,
Seifeddine.