Re: [RFC] Pattern Matching — missing keys and strict int
| From: | kevinblakelopez at gmail dot com | Date: | Thu, 22 Oct 2026 12:30:14 +0000 |
| Subject: | Re: [RFC] Pattern Matching — missing keys and strict int | ||
| Groups: | php.internals | ||
| Request: | Send a blank email to internals+get-132899@lists.php.net to get a copy of this message | ||
> Hello Larry and Ilija,
>
> I maintain a production PHP application that rejects a model’s JSON reply unless every field
> is present and of an exact type. Pattern matching is the language feature that would replace those
> checks. Two outcomes in the current draft would make that replacement accept replies we currently
> reject. Both are constraints on the rules you already wrote, not requests for new syntax.
>
> The RFC’s array-pattern equivalents use array_key_exists() before comparing the value. A
> missing key therefore fails the pattern. The implementation note on
> https://github.com/php/php-src/pull/20574 says the draft reads a
> missing element as null, so this is true:
>
> ['a' => 42] is ['b' => null]
>
> Please keep the RFC text. For this parser, a missing key and an explicit null are different
> successful results, and a value of any other type is a failure:
>
> function partQuote(array $p): ?array {
> if (!is_string($p['part'] ?? null)) {
> return null;
> }
> if (array_key_exists('quote', $p) && $p['quote'] !== null
> && !is_string($p['quote'])) {
> return null;
> }
> $out = ['part' => $p['part']];
> if (array_key_exists('quote', $p)) {
> $out['quote'] = $p['quote']; // null is kept; the key was
> present
> }
> return $out;
> }
>
> partQuote(['part' => 'A']); // ['part'
> => 'A']
> partQuote(['part' => 'A', 'quote' => null]); //
> ['part' => 'A', 'quote' => null]
> partQuote(['part' => 'A', 'quote' => 1]); // null
>
> If ['quote' => null] matched a missing quote, the first two calls would become the
> same pattern and the stored shape would be wrong.
>
> The same parser requires a real int for a score-like field, in 0..100 inclusive. is_int() is
> the type check; the range is applied only after that. These all fail:
>
> ['strength' => '80']
> ['strength' => 80.0]
> ['strength' => 101]
> ['relevant' => 1] // is_bool(), same rule: no coercion
> ['relevant' => 'true']
>
> and ['strength' => 80] with ['relevant' => true] passes. An int
> pattern therefore has to reject a numeric string and a float. A range pattern such as >=0 &
> <=100 has to do the same when it is standing in for that field; "80" and 80.0 are
> inside the numeric range and are still the wrong type.
>
> I am not asking for a change to the feature set. The written array patterns already say
> array_key_exists(), and an int pattern that follows is_int() is what this code can adopt.
>
> Kevin Lopez