PHP Predicates
last modified October 22, 2026
In this article, we explore predicates in PHP. A predicate is a function that returns a boolean value. Predicates are used to test conditions, filter collections, validate data, and make decisions in code.
Basic definition
A predicate takes one or more arguments and returns true or
false. In PHP, a predicate can be a named function, an anonymous
function, an arrow function, or a static or instance method. Functions such as
array_filter, array_find, array_any and
array_all accept predicates as callbacks. Many built-in functions,
like is_int or ctype_digit, are predicates
themselves.
Simple predicate
The following example defines a predicate that checks if a number is even.
<?php
declare(strict_types=1);
function isEven(int $number): bool
{
return $number % 2 === 0;
}
foreach ([4, 7, 0, -2] as $n) {
printf("%d is even: %s\n", $n, isEven($n) ? 'true' : 'false');
}
The isEven function returns true if the remainder
after division by two is zero. The bool return type documents that
the function is a predicate.
$ php simple.php 4 is even: true 7 is even: false 0 is even: true -2 is even: true
Filtering arrays with a named predicate
The following example uses a named function as a predicate for
array_filter.
<?php
declare(strict_types=1);
function isPositive(int $number): bool
{
return $number > 0;
}
$numbers = [-1, 2, -3, 4, -5];
$positive = array_filter($numbers, 'isPositive');
print_r($positive);
$positive = array_filter($numbers, isPositive(...));
print_r(array_values($positive));
A named function can be passed as a string, 'isPositive', or with
the first-class callable syntax isPositive(...), available since
PHP 8.1. The latter is checked by static analysis tools and IDEs.
Note that array_filter preserves the keys of the original array.
The array_values function renumbers them from zero.
$ php filter_named.php
Array
(
[1] => 2
[3] => 4
)
Array
(
[0] => 2
[1] => 4
)
Anonymous and arrow functions
Short predicates are often written inline.
<?php
declare(strict_types=1);
$numbers = [1, 2, 3, 4, 5, 6];
$even = array_filter($numbers, function (int $number): bool {
return $number % 2 === 0;
});
$odd = array_filter($numbers, fn(int $n): bool => $n % 2 !== 0);
echo implode(', ', $even), "\n";
echo implode(', ', $odd), "\n";
The first predicate is an anonymous function, the second an arrow function. An arrow function contains a single expression and captures variables of the enclosing scope automatically.
$ php anonymous.php 2, 4, 6 1, 3, 5
Validation predicates
Predicates are a natural fit for validation.
<?php
declare(strict_types=1);
function isValidEmail(string $email): bool
{
return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}
$emails = ['test@example.com', 'invalid-email', 'user@domain.com', 'user@.com'];
$valid = array_filter($emails, isValidEmail(...));
print_r($valid);
The isValidEmail predicate wraps filter_var, which
returns the filtered value on success and false on failure. The
strict comparison turns the result into a boolean.
$ php emails.php
Array
(
[0] => test@example.com
[2] => user@domain.com
)
Predicates on objects
A predicate can test properties of objects.
<?php
declare(strict_types=1);
final class User
{
public function __construct(public string $name, public int $age) {}
}
function isAdult(User $user): bool
{
return $user->age >= 18;
}
$users = [
new User("Peter", 15),
new User("Lucia", 20),
new User("Martin", 17),
new User("Eva", 34),
];
foreach (array_filter($users, isAdult(...)) as $user) {
echo "$user->name ($user->age)\n";
}
The isAdult predicate checks the age of a user. Only adults are
printed.
$ php objects.php Lucia (20) Eva (34)
Predicate factories
A function can create predicates with a configurable parameter.
<?php
declare(strict_types=1);
function longerThan(int $length): Closure
{
return fn(string $text): bool => mb_strlen($text) > $length;
}
function startsWith(string $prefix): Closure
{
return fn(string $text): bool => str_starts_with($text, $prefix);
}
$words = ['sky', 'skyscraper', 'small', 'smartphone', 'cloud'];
print_r(array_filter($words, longerThan(5)));
print_r(array_filter($words, startsWith('sm')));
The longerThan and startsWith functions return
closures. The arrow functions capture the $length and
$prefix parameters, so each call produces a new, specialized
predicate.
$ php factory.php
Array
(
[1] => skyscraper
[3] => smartphone
)
Array
(
[2] => small
[3] => smartphone
)
Combining predicates
Simple predicates can be combined into more complex ones with higher-order functions.
<?php
declare(strict_types=1);
function not(callable $p): Closure
{
return fn(mixed $x): bool => !$p($x);
}
function allOf(callable ...$ps): Closure
{
return function (mixed $x) use ($ps): bool {
foreach ($ps as $p) {
if (!$p($x)) {
return false;
}
}
return true;
};
}
function anyOf(callable ...$ps): Closure
{
return function (mixed $x) use ($ps): bool {
foreach ($ps as $p) {
if ($p($x)) {
return true;
}
}
return false;
};
}
$isEven = fn(int $n): bool => $n % 2 === 0;
$isPositive = fn(int $n): bool => $n > 0;
$isBig = fn(int $n): bool => abs($n) > 100;
$numbers = [-150, -4, -3, 0, 7, 12, 250];
echo implode(' ', array_filter($numbers, allOf($isEven, $isPositive))), "\n";
echo implode(' ', array_filter($numbers, not($isEven))), "\n";
echo implode(' ', array_filter($numbers, anyOf($isBig, not($isPositive)))), "\n";
The not function negates a predicate, allOf requires
all predicates to pass, and anyOf requires at least one. The
combined predicates are built from three small ones, which keeps each condition
readable and testable.
$ php combinators.php 12 250 -3 7 -150 -4 -3 0 250
Testing keys and values
By default, array_filter passes only values to the predicate. A
flag changes this.
<?php
declare(strict_types=1);
$stock = ['apples' => 12, 'pears' => 0, 'plums' => 5, 'peaches' => 0];
$inStock = array_filter($stock, fn(int $qty): bool => $qty > 0);
print_r($inStock);
$startsWithP = array_filter($stock, fn(string $key): bool => $key[0] === 'p',
ARRAY_FILTER_USE_KEY);
print_r($startsWithP);
$both = array_filter($stock, fn(int $qty, string $key): bool => $qty > 0 && $key[0] === 'p',
ARRAY_FILTER_USE_BOTH);
print_r($both);
With ARRAY_FILTER_USE_KEY, the predicate receives the key; with
ARRAY_FILTER_USE_BOTH, it receives the value and the key.
$ php keys.php
Array
(
[apples] => 12
[plums] => 5
)
Array
(
[pears] => 0
[plums] => 5
[peaches] => 0
)
Array
(
[plums] => 5
)
array_find, array_any and array_all
PHP 8.4 added four functions that use predicates to search arrays.
<?php declare(strict_types=1); $temperatures = ['Mon' => 18, 'Tue' => 21, 'Wed' => 26, 'Thu' => 29, 'Fri' => 24]; $isHot = fn(int $t): bool => $t > 25; echo "First hot day: ", array_find_key($temperatures, $isHot), "\n"; echo "First hot temperature: ", array_find($temperatures, $isHot), "\n"; var_dump(array_any($temperatures, $isHot)); var_dump(array_all($temperatures, fn(int $t): bool => $t > 15)); var_dump(array_find($temperatures, fn(int $t): bool => $t > 40));
array_find returns the first value that satisfies the predicate
and array_find_key its key; both return null when
nothing matches. array_any checks whether at least one element
satisfies the predicate and array_all whether all of them do. All
four stop as soon as the result is known. The predicate also receives the key as
its second argument.
$ php find_any_all.php First hot day: Wed First hot temperature: 26 bool(true) bool(true) NULL
Built-in predicates
PHP has many built-in predicate functions that can be passed directly as callbacks.
<?php
declare(strict_types=1);
$values = [1, '2', 3.5, 'sky', null, true, [], '42'];
echo "ints: ", count(array_filter($values, 'is_int')), "\n";
echo "strings: ", count(array_filter($values, 'is_string')), "\n";
echo "numeric: ", count(array_filter($values, 'is_numeric')), "\n";
$digits = array_filter(['123', '12a', '007', ''], 'ctype_digit');
print_r($digits);
$words = preg_grep('/^s/', ['sky', 'cloud', 'sun', 'rain']);
print_r($words);
The is_* functions test types, is_numeric accepts
numbers and numeric strings, and ctype_digit tests whether a
string consists of digits only. The preg_grep function filters an
array with a regular expression, which works like a predicate.
$ php builtin.php
ints: 1
strings: 3
numeric: 4
Array
(
[0] => 123
[2] => 007
)
Array
(
[0] => sky
[2] => sun
)
Source
PHP array_filter - Documentation
In this article, we have shown how to write predicates in PHP, how to create and combine them, and how to use them for filtering, searching, and validation.
Author
List all PHP tutorials.