[GIT-PULLS] [php-src] PR #23403: ext/filter: Narrow the return type of filter_var_array() to array|false
[email protected] (lacatoire)
| Newsgroups | php.git-pulls |
|---|---|
| Message-ID | <[email protected]> |
Pull Request: https://github.com/php/php-src/pull/23403
Author: lacatoire
`filter_var_array()` declares `array|false|null`, but `null` is unreachable.
The function has exactly two exits: `RETURN_FALSE` when the filter id is unknown, and `php_filter_array_handler()`, which establishes an array on both of its branches before doing anything else — `ZVAL_DUP()` of the input, which is a `Z_PARAM_ARRAY`, or `array_init()`. The handler's remaining exits are `RETURN_THROWS()`.
The sibling `filter_input_array()` is declared identically and does return `null`, deliberately, since its source superglobal may not exist:
```c
if (!array_input) {
RETURN_NULL();
}
```
That case has no equivalent in `filter_var_array()`, whose source is a required `array` parameter. The two signatures look symmetrical but only one of them can produce `null`.
## Verification
Swept every registered filter from `filter_list()`, as the global int form and inside an options array, across six flag combinations including `FILTER_NULL_ON_FAILURE`, `FILTER_FORCE_ARRAY` and `FILTER_REQUIRE_SCALAR`, against inputs chosen to make filters fail, with `$add_empty` both ways. 3024 calls on 8.5.4: `array` 2848 times, `TypeError` 88, `ValueError` 88, plus `false` for the unknown filter id. `null` never appears.
Worth noting that `null` remains an ordinary **element** value in the returned array, which is likely where the wider union came from:
```php
filter_var_array(['a' => 'x'], ['a' => ['filter' => FILTER_VALIDATE_BOOLEAN, 'flags' => FILTER_NULL_ON_FAILURE]]);
```
That is the value type, not the return type.
Only the stub changes; the arginfo is regenerated and the edit is confined to `arginfo_filter_var_array`, `filter_input_array` keeps `MAY_BE_NULL`.
## Note
This is behaviour-preserving on the engine side, but it does tighten what userland is told, and it shows up in `ReflectionFunction::getReturnType()`. Whether that belongs in a minor or should wait for a major is the maintainers' call.