PHP · RFC Watch
PHP pattern matching debate turns on keys and ints
Kevin Lopez has raised two semantic issues in the draft PHP Pattern Matching RFC.
Array patterns should distinguish a missing key from an explicit null and use array_key_exists(). Integer patterns and numeric ranges should reject strings and floats, even when their values fit. Lopez says these rules are required to validate model JSON with exact fields and types.
Kevin Lopez addressed Larry and Ilija in a PHP Internals discussion about the draft Pattern Matching RFC. He maintains a production PHP application that rejects a model's JSON response when a field is missing or has the wrong type. Lopez says the current draft could accept two responses that this application must reject.
<?php
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;
}The RFC's array-pattern rules use array_key_exists() before comparing a value. An implementation note in php/php-src pull request 20574 says the draft reads a missing element as null. That would make `['a' => 42]` match `['b' => null]`. Lopez asks the authors to keep the existing RFC wording because his parser treats an absent key and a present key containing null as different states.
His `partQuote()` example requires `part` to be a string. `quote` may be absent, null, or a string, but another type returns null. The output keeps the `quote` key when it was supplied. As a result, `partQuote(['part' => 'A'])` returns `['part' => 'A']`. A call with `quote` set to null keeps that key in the output. A numeric quote returns null.
The second issue concerns a score-like field. The parser requires `strength` to pass is_int() before applying the inclusive 0 through 100 range. `'80'` fails because it is a string, and `80.0` fails because it is a float. `101` is outside the range. For `relevant`, the same no-coercion rule uses is_bool(): both `1` and `'true'` fail. `strength` 80 together with `relevant` true passes. Lopez says an int pattern and a range pattern such as `>=0 & <=100` must reject numeric strings and floats when used for this field. He is asking for the existing rules to be applied consistently, not for new syntax.
Readers’ Forum
No contributions yet — open the debate.
Open the discussion
No account or password needed — just enter your e-mail and we’ll send you a one-time sign-in link. First time here? You’re set up automatically.
Your rating will be applied automatically after you sign in.
Check your inbox
We’ve sent a sign-in link to …. Open it on this device — this tab will sign you in automatically.
Nothing arrived? Check your spam folder — and mark the mail as "Not spam" so it lands in your inbox next time.