PHP 8.4.2 Released!

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

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

Операторы сравнения
Пример Название Результат
$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 Массив с меньшим количеством элементов меньше, если PHP не нашёл ключ из первого массива во втором массиве — массивы несравнимы, иначе идёт сравнение значения за значением (смотрите пример ниже)
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

?>

Добавить

Примечания пользователей 13 notes

up
173
crazy888s at hotmail dot com
14 years ago
I couldn't find much info on stacking the new ternary operator, so I ran some tests:

<?php
echo 0 ?: 1 ?: 2 ?: 3; //1
echo 1 ?: 0 ?: 3 ?: 2; //1
echo 2 ?: 1 ?: 0 ?: 3; //2
echo 3 ?: 2 ?: 1 ?: 0; //3

echo 0 ?: 1 ?: 2 ?: 3; //1
echo 0 ?: 0 ?: 2 ?: 3; //2
echo 0 ?: 0 ?: 0 ?: 3; //3
?>

It works just as expected, returning the first non-false value within a group of expressions.
up
8
Sumon Mahmud
4 years ago
Extending from here: https://www.php.net/manual/en/language.operators.comparison.php#121907

$a = ['a' => 1, 'b' => 2, 'c' => 3, 'e' => 4];
$b = ['a' => 1, 'b' => 2, 'd' => 3, 'e' => 4];

echo $a > $b; // 0
echo $b > $a; // 0
echo $a <$b; // 0
echo $b < $a; // 0

If using spaceship operator then it is returning true like :

echo $a <=> $b; //1
echo $b <=> $a; //1
echo $a <=> $b; //1
echo $b <=> $a; //1
up
3
Hayley Watson
1 year ago
Between the "shortcut ternary" (aka "elvis") and "spaceship" operators, you can write some quite compact comparison functions for usort and its ilk.

If you want to sort an array of associative arrays by several different keys you can chain them in the same way that you can list column names in an SQL ORDER BY clause.

<?php
usort
($array, fn($a, $b) => $a['a'] <=> $b['a']
?:
$b['b'] <=> $a['b']
?:
$a['c'] <=> $b['c']);
?>
Will sort the array by column 'a', then by column 'b' descending, then by column 'c'; or in SQL-speak 'ORDER BY a, b DESC, c".
up
23
adam at caucho dot com
18 years ago
Note: according to the spec, PHP's comparison operators are not transitive. For example, the following are all true in PHP5:

"11" < "a" < 2 < "11"

As a result, the outcome of sorting an array depends on the order the elements appear in the pre-sort array. The following code will dump out two arrays with *different* orderings:

<?php
$a
= array(2, "a", "11", 2);
$b = array(2, "11", "a", 2);
sort($a);
var_dump($a);
sort($b);
var_dump($b);
?>

This is not a bug report -- given the spec on this documentation page, what PHP does is "correct". But that may not be what was intended...
up
9
Tahazzot
3 years ago
Very careful when reading PHP documentation, Here's a lot of miss information.

According to documentation, They say's (int) 0 == (string) "a" is true. But it is not in PHP 8.

var_dump(0 == "a"); // 0 == 0 -> true

Now In PHP 8 it's False.
up
8
admin at zeros dot co dot id
2 years ago
Please be careful when you try to compare strings that have a plus sign `+` at the beginning (such as phone number, etc). When you use the Equal operator `==` PHP will ignore the plus sign. Use Identical operator `===` instead

Example:

$str1 = "62";
$str2 = "+62";

var_dump($str1 == $str2); // bool(true)
var_dump($str1 === $str2); // bool(false)
up
18
rshawiii at yahoo dot com
18 years ago
You can't just compare two arrays with the === operator
like you would think to find out if they are equal or not. This is more complicated when you have multi-dimensional arrays. Here is a recursive comparison function.

<?php
/**
* Compares two arrays to see if they contain the same values. Returns TRUE or FALSE.
* usefull for determining if a record or block of data was modified (perhaps by user input)
* prior to setting a "date_last_updated" or skipping updating the db in the case of no change.
*
* @param array $a1
* @param array $a2
* @return boolean
*/
function array_compare_recursive($a1, $a2)
{
if (!(
is_array($a1) and (is_array($a2)))) { return FALSE;}

if (!
count($a1) == count($a2))
{
return
FALSE; // arrays don't have same number of entries
}

foreach (
$a1 as $key => $val)
{
if (!
array_key_exists($key, $a2))
{return
FALSE; // uncomparable array keys don't match
}
elseif (
is_array($val) and is_array($a2[$key])) // if both entries are arrays then compare recursive
{if (!array_compare_recursive($val,$a2[$key])) return FALSE;
}
elseif (!(
$val === $a2[$key])) // compare entries must be of same type.
{return FALSE;
}
}
return
TRUE; // $a1 === $a2
}
?>
up
3
gfilippakis at sleed dot gr
1 year ago
Please note that using the null coalescing operator to check properties on a class that has the __get magic method (without an __isset magic method) invokes the magic method.

For example:

<?php

class A
{
public function
__get($property)
{
echo
'Called __get for ' . $property . PHP_EOL;
}
}

$a = new A();

echo
'Trying null coalescing operator' . PHP_EOL;
$b = $a->test ?? 5;

echo
'Trying isset()' . PHP_EOL;
if (isset(
$a->test)) {
$b = $a->test;
} else {
$b = 5;
}

?>
up
13
bishop
18 years ago
When you want to know if two arrays contain the same values, regardless of the values' order, you cannot use "==" or "===". In other words:

<?php
(array(1,2) == array(2,1)) === false;
?>

To answer that question, use:

<?php
function array_equal($a, $b) {
return (
is_array($a) && is_array($b) && array_diff($a, $b) === array_diff($b, $a));
}
?>

A related, but more strict problem, is if you need to ensure that two arrays contain the same key=>value pairs, regardless of the order of the pairs. In that case, use:

<?php
function array_identical($a, $b) {
return (
is_array($a) && is_array($b) && array_diff_assoc($a, $b) === array_diff_assoc($b, $a));
}
?>

Example:
<?php
$a
= array (2, 1);
$b = array (1, 2);
// true === array_equal($a, $b);
// false === array_identical($a, $b);

$a = array ('a' => 2, 'b' => 1);
$b = array ('b' => 1, 'a' => 2);
// true === array_identical($a, $b)
// true === array_equal($a, $b)
?>

(See also the solution "rshawiii at yahoo dot com" posted)
up
4
niall at maranelda dot org
7 years ago
Care must be taken when using the spaceship operator with arrays that do not have the same keys:

- Contrary to the notes above ("Example #2 Transcription of standard array comparison"), it does *not* return null if the left-hand array contains a key that the right-hand array does not.
- Because of this, the result depends on the order you do the comparison in.

For example:

<?php
$a
= ['a' => 1, 'b' => 2, 'c' => 3, 'e' => 4];
$b = ['a' => 1, 'b' => 2, 'd' => 3, 'e' => 4];

var_dump($a <=> $b); // int(1) : $a > $b because $a has the 'c' key and $b doesn't.

var_dump($b <=> $a); // int(1) : $b > $a because $b has the 'd' key and $a doesn't.
?>
up
3
Ryan Mott
5 years ago
Searching for "double question mark" operator should find this page (and hopefully after this comment the crawlers will agree)
up
6
Cuong Huy To
13 years ago
In the table "Comparison with Various Types", please move the last line about "Object" to be above the line about "Array", since Object is considered to be greater than Array (tested on 5.3.3)

(Please remove my "Anonymous" post of the same content before. You could check IP to see that I forgot to type my name)
up
2
Marcin Kuzawiski
9 years ago
A < B and still B < A...

$A = [1 => 1, 2 => 0, 3 => 1];
$B = [1 => 1, 3 => 0, 2 => 1];

var_dump($A < $B); // TRUE
var_dump($B < $A); // TRUE

var_dump($A > $B); // TRUE
var_dump($B > $A); // TRUE

Next - C and D are comparable, but neither C < D nor D < C (and still C != D)...

$C = [1 => 1, 2 => 1, 3 => 0];
$D = [1 => 1, 3 => 1, 2 => 0];

var_dump($C < $D); // FALSE
var_dump($D < $C); // FALSE

var_dump($C > $D); // FALSE
var_dump($D > $C); // FALSE

var_dump($D == $C); // FALSE
To Top