PHP RFC: FILTER_THROW_ON_FAILURE
- Version: 0.1
- Date: 2025-06-21
- Author: Daniel Scherzer, daniel.e.scherzer@gmail.com
- Status: Under discussion
- Implementation: https://github.com/php/php-src/pull/18896
Introduction
The filter extension (ext/filter) can be used to verify that values (either given as variables or extracted from various superglobals like $_GET
) match specified filters (like being a valid email address). Normally, when a value fails validation, false
is returned (or when validating an array, false
is used for just that array key). With the FILTER_NULL_ON_FAILURE
flag, the result is null
instead of false. We propose to add a new flag to have the filter extension throw exceptions on failure: FILTER_THROW_ON_FAILURE
.
Developers that require that input match a certain filter will frequently call the filter function and then manually throw an exception if the result is false
(or null
with FILTER_NULL_ON_FAILURE
). Additionally, both false
and null
are valid results for successful filtering, e.g. when using a callback. Thus, merely checking the return value is not always enough to know if validation succeeded or not.
This new flag is similar to JSON_THROW_ON_ERROR
and was inspired by json_throw_on_error.
Proposal
A new filter flag is added, FILTER_THROW_ON_FAILURE
, that triggers an exception whenever a filter's validation fails.
In keeping with the recent RFC: Throwable Hierarchy Policy for Extensions, a new base class Filter\FilterException
is added, and it is extended by Filter\FilterFailedException
, which is what gets thrown when validation fails:
namespace Filter { class FilterException extends \Exception {} class FilterFailedException extends FilterException {} }
The flag can be used in the same places that other flags are.
The new flag cannot be combined with FILTER_NULL_ON_FAILURE
; trying to do so will result in a ValueError
being thrown.
Examples
Existing code written like:
function validateUser($email, $userId, $userName) { if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) { return false; } if (filter_var($userId, FILTER_VALIDATE_INT) === false) { return false; } if (filter_var( $userName, FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => '/^[a-z]+$/']] ) === false) { return false; } return true; }
could instead be simplified to:
function validateUser($email, $userId, $userName) { try { filter_var($email, FILTER_VALIDATE_EMAIL, FILTER_THROW_ON_FAILURE); filter_var($userId, FILTER_VALIDATE_INT, FILTER_THROW_ON_FAILURE); filter_var( $userName, FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => '/^[a-z]+$/'], 'flags' => FILTER_THROW_ON_FAILURE] ); return true; } catch (\Filter\FilterFailedException $e) { return false; } }
reducing the duplication around checking return results.
Backward Incompatible Changes
New global constant FILTER_THROW_ON_FAILURE
is added; 2025.07.05 GitHub search for "FILTER_THROW_ON_FAILURE"
had no hits.
New class \Filter\FilterException
is added; 2025.07.05 GitHub search for /(class|interface|trait|enum) FilterException/ lang:php -is:fork
yielded 269 hits for code; from what I saw none are in a namespace named Filter
.
New class \Filter\FilterFailedException
is added; 2025.07.05 GitHub search for /(class|interface|trait|enum) FilterFailedException/ lang:php -is:fork
yielded a single hit, which is in a different namespace.
Proposed PHP Version(s)
PHP 8.5
RFC Impact
To Existing Extensions
Only ext/filter is impacted.
Voting Choices
Add FILTER_THROW_ON_FAILURE
and the associated exception classes?
Patches and Tests
Implementation
After the RFC is implemented, this section should contain:
- the version(s) it was merged into
- a link to the git commit(s)
- a link to the PHP manual entry for the feature
References
- Feature request on GitHub, https://github.com/php/php-src/issues/16710