rfc:filter_throw_on_failure

PHP RFC: FILTER_THROW_ON_FAILURE

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?

Add FILTER_THROW_ON_FAILURE and the associated exception classes?
Real name Yes No
Final result: 0 0
This poll has been closed.

Patches and Tests

Implementation

After the RFC is implemented, this section should contain:

  1. the version(s) it was merged into
  2. a link to the git commit(s)
  3. a link to the PHP manual entry for the feature

References

rfc/filter_throw_on_failure.txt · Last modified: by daniels