Skip to content

ext/filter: Narrow the return type of filter_var_array() to array|false - #23403

Merged
kocsismate merged 2 commits into
php:masterfrom
lacatoire:fix/filter-var-array-return-type
Aug 31, 2026
Merged

ext/filter: Narrow the return type of filter_var_array() to array|false#23403
kocsismate merged 2 commits into
php:masterfrom
lacatoire:fix/filter-var-array-return-type

Conversation

@lacatoire

Copy link
Copy Markdown
Member

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:

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:

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.

@LamentXU123 LamentXU123 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, In zend_func_infos.h L98

	F1("filter_var_array", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_FALSE|MAY_BE_NULL),

MAY_BE_NULL is still in there. So you will need to also remove this.

@kocsismate

Copy link
Copy Markdown
Member

@lacatoire you should run gen_stub.php --generate-optimizer-info

The stub declares array|false|null, but null is unreachable. The function
has two exits: RETURN_FALSE for an unknown filter id, and the array handler,
which establishes an array on both of its branches before doing anything
else. Its remaining exits throw.

The sibling filter_input_array() is declared identically and does return
null, deliberately, because its source superglobal may not exist. That case
has no equivalent here, where the source is a required array parameter.

null remains an ordinary element value in the returned array, which is
likely where the wider union came from; that is the value type, not the
return type.
@lacatoire
lacatoire force-pushed the fix/filter-var-array-return-type branch from 996a5f0 to e2a7b0a Compare August 25, 2026 19:01
@lacatoire
lacatoire requested a review from dstogov as a code owner August 25, 2026 19:01

@kocsismate kocsismate left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM if the tests also pass which I restarted.

@Sjord

Sjord commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Looks good to me.

Test failure seems unrelated.

@kocsismate

Copy link
Copy Markdown
Member

The other recent type narrowing changes had an upgrading note. could you add one please for consistency?

@kocsismate
kocsismate merged commit f74c740 into php:master Aug 31, 2026
17 of 18 checks passed
@lacatoire
lacatoire deleted the fix/filter-var-array-return-type branch August 31, 2026 12:34
Comment thread UPGRADING
- Filter:
. filter_var_array() return type has been narrowed from array|false|null to
array|false. The function always establishes an array before filtering, so
null was never returned. filter_input_array() is unaffected: it still

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part is clearly from AI and should be removed

filter_input_array() is unaffected: it returns null when the requested superglobal does not exist.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants