Операторы сравнения

Операторы сравнения, как это видно из их названия, разрешают сравнивать между собой два значения. Могут также оказаться интересными для знакомства таблицы сравнения типов, поскольку в них показаны примеры сравнений, связанных с разными типами.

Операторы сравнения
Пример Название Результат
$a == $b Равно Возвращается true, если значение переменной $a после преобразования типов равно значению переменной $b.
$a === $b Тождественно равно Возвращается true, если значение переменной $a равно значению переменной $b и имеет тот же тип.
$a != $b Не равно Возвращается true, если значение переменной $a после преобразования типов не равно значению переменной $b.
$a <> $b Не равно Возвращается true, если значение переменной $a после преобразования типов не равно значению переменной $b.
$a !== $b Тождественно не равно Возвращается true, если значение переменной $a не равно значению переменной $b или они разных типов.
$a < $b Меньше Возвращается true, если значение переменной $a строго меньше значения переменной $b.
$a > $b Больше Возвращается true, если значение переменной $a строго больше значения переменной $b.
$a <= $b Меньше или равно Возвращается true, если значение переменной $a меньше или равно значению переменной $b.
$a >= $b Больше или равно Возвращается true, если значение переменной $a больше или равно значению переменной $b.
$a <=> $b Космический корабль (spaceship) Целое число (int) меньше, больше или равное нулю, когда значение переменной $a меньше, больше или равно значению переменной $b.

Если оба операнда — строки, содержащие числа, или один операнд — число, а другой — строка, содержащая числа, то сравнение выполняется численно. Эти правила также справедливы для оператора switch. Тип не преобразовывается при сравнениях вида === или !==, поскольку это включает сравнение типа, а также значения.

Внимание

До PHP 8.0.0, если строка (string) сравнивалась с числом или строкой, содержащей число, то строка (string) преобразовывалась в число перед выполнением сравнения. Это могло привести к неожиданным результатам, что можно увидеть на следующем примере:

<?php

var_dump
(0 == "a");
var_dump("1" == "01");
var_dump("10" == "1e1");
var_dump(100 == "1e2");

switch (
"a") {
case
0:
echo
"0";
break;
case
"a":
echo
"a";
break;
}

Результат выполнения приведённого примера в PHP 7:

bool(true)
bool(true)
bool(true)
bool(true)
0

Результат выполнения приведённого примера в PHP 8:

bool(false)
bool(true)
bool(true)
bool(true)
a

<?php
// Целые числа
echo 1 <=> 1; // 0
echo 1 <=> 2; // -1
echo 2 <=> 1; // 1

// Числа с плавающей точкой
echo 1.5 <=> 1.5; // 0
echo 1.5 <=> 2.5; // -1
echo 2.5 <=> 1.5; // 1

// Строки
echo "a" <=> "a"; // 0
echo "a" <=> "b"; // -1
echo "b" <=> "a"; // 1
echo "a" <=> "aa"; // -1
echo "zz" <=> "aa"; // 1

// Массивы
echo [] <=> []; // 0
echo [1, 2, 3] <=> [1, 2, 3]; // 0
echo [1, 2, 3] <=> []; // 1
echo [1, 2, 3] <=> [1, 2, 1]; // 1
echo [1, 2, 3] <=> [1, 2, 4]; // -1

// Объекты
$a = (object) ["a" => "b"];
$b = (object) ["a" => "b"];
echo
$a <=> $b; // 0
$a = (object) ["a" => "b"];
$b = (object) ["a" => "c"];
echo
$a <=> $b; // -1
$a = (object) ["a" => "c"];
$b = (object) ["a" => "b"];
echo
$a <=> $b; // 1

// сравниваются не только значения; ключи также должны совпадать
$a = (object) ["a" => "b"];
$b = (object) ["b" => "b"];
echo
$a <=> $b; // 1
?>

Для различных типов сравнение происходит в соответствии со следующей таблицей (по порядку).

Сравнение типов
Тип операнда 1 Тип операнда 2 Результат
null или string string null преобразуется в пустую строку (""), числовое или лексическое сравнение
bool или null что угодно Преобразуется в bool, false < true
object object Встроенные классы могут определять свои правила сравнения, объекты разных классов не сравниваются, про сравнение объектов одного класса рассказано в разделе «Сравнение объекта»
string, resource, int или float string, resource, int или float Строки и ресурсы переводятся в числа, обычная математика
array array Массив с меньшим числом элементов меньше, если ключ из первого массива не найден во втором массиве — массивы не могут сравниваться, иначе идёт сравнение значений (смотрите пример ниже)
array что угодно Тип array всегда больше
object что угодно Тип object всегда больше

Пример #1 Сравнение boolean/null

<?php

// Логические значения и null всегда сравниваются как логические
var_dump(1 == TRUE); // TRUE — то же, что и (bool)1 == TRUE
var_dump(0 == FALSE); // TRUE — то же, что и (bool)0 == FALSE
var_dump(100 < TRUE); // FALSE — то же, что и (bool)100 < TRUE
var_dump(-10 < FALSE); // FALSE — то же, что и (bool)-10 < FALSE
var_dump(min(-100, -10, NULL, 10, 100)); // NULL — (bool)NULL < (bool)-100 это FALSE < TRUE

Пример #2 Алгоритм сравнения обычных массивов

<?php

// Массивы сравниваются как в этом примере — со стандартными операторами сравнения, а также оператором «космический корабль» (spaceship).
function standard_array_compare($op1, $op2)
{
if (
count($op1) < count($op2)) {
return -
1; // $op1 < $op2
} elseif (count($op1) > count($op2)) {
return
1; // $op1 > $op2
}

foreach (
$op1 as $key => $val) {
if (!
array_key_exists($key, $op2)) {
return
1;
} elseif (
$val < $op2[$key]) {
return -
1;
} elseif (
$val > $op2[$key]) {
return
1;
}
}

return
0; // $op1 == $op2
}

Внимание

Сравнение чисел с плавающей точкой

По причинам, связанным со способом внутреннего представления чисел с плавающей точкой (float), не нужно проверять два числа с плавающей точкой (float) на равенство.

Подробнее об этом можно узнать в документации по типу float.

Замечание: Когда пишут код, помнят, что жонглирование типами в PHP не всегда даёт предсказуемый результат при сравнении значений разных типов, особенно при сравнении целых чисел (int) с логическими значениями (bool) или целых чисел (int) со строками (string). Поэтому лучше пользоваться операторами === и !==, а не == и !=.

Несравнимые значение

Хотя тождественные сравнения (=== и !==) можно применять к произвольным значениям, другие операторы сравнения лучше применять только к сравнимым значениям. Результат сравнения несравнимых значений не определён и на него не нужно полагаться.

Тернарный оператор

Ещё один условный оператор — тернарный оператор «?:».

Пример #3 Присваивание значения по умолчанию

<?php

// Пример выражения с тернарным оператором
$action = (empty($_POST['action'])) ? 'default' : $_POST['action'];

// Код выше аналогичен блоку с конструкциями if/else
if (empty($_POST['action'])) {
$action = 'default';
} else {
$action = $_POST['action'];
}
Выражение (expr1) ? (expr2) : (expr3) интерпретируется как expr2, если expr1 равно true, или как expr3, если expr1 равно false.

Можно не писать среднюю часть тернарного оператора. Выражение expr1 ?: expr3 оценивается как результат выражения expr1, если оно оценивается как true, иначе как результат выражения expr3. Выражение expr1 оценивается только один раз.

Замечание: Обратите внимание, что тернарный оператор — это выражение, и он оценивается не как переменная, а как результат выражения. Это важно, если нужно вернуть переменную по ссылке. Выражение return $var == 42 ? $a : $b; не будет работать в функции, возвращающей значение по ссылке, а в более поздних версиях PHP также будет выдано предупреждение.

Замечание:

Рекомендовано избегать «нагромождения» тернарных выражений. Поведение PHP при указании более чем одного тернарного оператора без скобок в одном выражении неочевидно в сравнении с другими языками. Впрямь, до PHP 8.0.0 троичные выражения оценивались как левоассоциативные, а не правоассоциативные, как в большей части других языков программирования. Опора на левую ассоциативность устарела начиная с PHP 7.4.0. Начиная с PHP 8.0.0 тернарный оператор неассоциативен.

Пример #4 Неочевидное поведение тернарного оператора

<?php

// кажется, что следующий код выведет «true»
echo (true ? 'true' : false ? 't' : 'f');

// однако он выводит «t» до PHP 8.0.0
// это потому, что тернарные выражения левоассоциативны

// следующая запись — более очевидная версия того же кода, который показан выше
echo ((true ? 'true' : false) ? 't' : 'f');

// здесь видно, что первое выражение оценивается как строковое «true», которое
// оценивается как логическое (bool) true, поэтому возвращает истинную ветвь
// второго тернарного выражения.

Замечание:

Цепочка коротких тернарных операторов (?:), однако, стабильна и ведёт себя обоснованно. Она будет оценивать первый аргумент, который оценивается как не ложное значение. Обратите внимание, что неопределённые значения все равно вызовут предупреждение.

Пример #5 Цепочка коротких тернарных операторов

<?php
echo 0 ?: 1 ?: 2 ?: 3, PHP_EOL; // 1
echo 0 ?: 0 ?: 2 ?: 3, PHP_EOL; // 2
echo 0 ?: 0 ?: 0 ?: 3, PHP_EOL; // 3
?>

Оператор объединения с null

Другой полезный сокращённый оператор — это оператор объединения с NULL — «??» (null coalescing).

Пример #6 Присваивание значения по умолчанию

<?php

// Пример работы с оператором нулевого слияния
$action = $_POST['action'] ?? 'default';

// Пример выше аналогичен этому выражению с if/else
if (isset($_POST['action'])) {
$action = $_POST['action'];
} else {
$action = 'default';
}
Выражение (expr1) ?? (expr2) вычисляется так: expr2, если expr1 равно null, иначе expr1.

Этот оператор не вызывает предупреждения или ошибки, если левый операнд не существует, точно как языковая конструкция isset(). Это очень полезно для ключей массива.

Замечание: Обратите внимание, оператор объединения с NULL — это выражение, и он оценивается не как переменная, а как результат вычисления выражения. Это важно, если нужно вернуть значение по ссылке. Выражение return $foo ?? $bar; в функции, возвращающей ссылку, будет не работать, а выводить предупреждение.

Замечание:

У оператора объединения с NULL низкий приоритет. То есть при смешивании его с другими операторами (например, с операторами конкатенации строк или арифметическими операторами), скорее всего, потребуются круглые скобки.

<?php

// Вызывает предупреждение о том, что $name не определено.
print 'Mr. ' . $name ?? 'Anonymous';

// Выведет "Mr. Anonymous"
print 'Mr. ' . ($name ?? 'Anonymous');

Замечание:

Обратите внимание, оператор объединения с NULL разрешает простую вложенность:

Пример #7 Вложенный оператор null coalescing

<?php

$foo
= null;
$bar = null;
$baz = 1;
$qux = 2;

echo
$foo ?? $bar ?? $baz ?? $qux; // выведет 1