Операторы сравнения
Операторы сравнения, как это видно из их названия, позволяют сравнивать между собой два значения. Возможно вам будет интересно также ознакомиться с разделом Сравнение типов, в котором приведено большое количество соответствующих примеров.
Пример | Название | Результат |
---|---|---|
$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"); // 0 == 0 -> true
var_dump("1" == "01"); // 1 == 1 -> true
var_dump("10" == "1e1"); // 10 == 10 -> true
var_dump(100 == "1e2"); // 100 == 100 -> true
switch ("a") {
case 0:
echo "0";
break;
case "a": // никогда не достигнет, потому что "a" уже совпало с 0
echo "a";
break;
}
?>
<?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
// Так сравниваются массивы при сравнении стандартными операторами
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 null; // не могут быть сравнимы
} elseif ($val < $op2[$key]) {
return -1;
} elseif ($val > $op2[$key]) {
return 1;
}
}
return 0; // $op1 == $op2
}
?>
Сравнение чисел с плавающей запятой
Из-за особого внутреннего представления типа float, не нужно проверять на равенство два числа с плавающей запятой (float).
Для более подробной информации смотрите документацию по типу float.
Тернарный оператор
Еще одним условным оператором является тернарный оператор "?:".
Пример #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 если expr1
имеет значение true
и expr3 в противном случае.
Замечание: Обратите внимание, что тернарный оператор является выражением и трактуется не как переменная, а как результат выражения. Это важно знать, если вы хотите вернуть переменную по ссылке. Выражение
return $var == 42 ? $a : $b;
не будет работать в функции, возвращающей значение по ссылке, а в более поздних версиях PHP также будет выдано предупреждение.
Замечание:
Рекомендуется избегать "нагромождения" тернарных выражений. Поведение PHP неочевидно при использовании нескольких тернарных операторов в одном выражении неочевидно по сравнению с другими языками. Действительно, до 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, таким образом возвращая истинную ветвь
// второго тернарного выражения.
?>
Оператор объединения с null
Также добавился новый оператор "??" (null coalescing).
Пример #5 Присваивание значения по умолчанию
<?php
// Пример использования оператора
$action = $_POST['action'] ?? 'default';
// Пример выше аналогичен следующему коду
if (isset($_POST['action'])) {
$action = $_POST['action'];
} else {
$action = 'default';
}
?>
(expr1) ?? (expr2)
вычисляется так:
expr2, если expr1 равен
null
и expr1 в противном случае.
На практике, этот оператор не вызывает предупреждения или ошибки, если левый операнд не существует, как и isset(). Это очень полезно для ключей массива.
Замечание: Пожалуйста помните, что этот оператор является выражением, и он приравнивается к выражению, а не значению переменной. Это может быть важным, если вы хотите вернуть значение по ссылке. Выражение
return $foo ?? $bar;
в функции возвращающей ссылку будет не работать, а выводить предупреждение.
Замечание:
Обратите внимание, что этот оператор позволяет использовать простую вложенность:
Пример #6 Вложенный оператор null coalescing
<?php
$foo = null;
$bar = null;
$baz = 1;
$qux = 2;
echo $foo ?? $bar ?? $baz ?? $qux; // выведет 1
?>