mirror of
https://github.com/php/doc-ru.git
synced 2026-04-25 16:28:19 +02:00
608 lines
23 KiB
XML
608 lines
23 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
||
<!-- EN-Revision: 43d07782b514d0c7a8487f2c74063739f302df8d Maintainer: sergey Status: ready -->
|
||
<!-- Reviewed: no -->
|
||
<sect1 xml:id="language.operators.comparison">
|
||
<title>Операторы сравнения</title>
|
||
<titleabbrev>Сравнение</titleabbrev>
|
||
<simpara>
|
||
Операторы сравнения, как это видно из их названия, разрешают сравнивать между собой
|
||
два значения. Могут также оказаться интересными для знакомства
|
||
<link linkend="types.comparisons">таблицы сравнения типов</link>,
|
||
поскольку в них показаны примеры сравнений, связанных с разными типами.
|
||
</simpara>
|
||
<table>
|
||
<title>Операторы сравнения</title>
|
||
<tgroup cols="3">
|
||
<thead>
|
||
<row>
|
||
<entry>Пример</entry>
|
||
<entry>Название</entry>
|
||
<entry>Результат</entry>
|
||
</row>
|
||
</thead>
|
||
<tbody>
|
||
<row>
|
||
<entry>$a == $b</entry>
|
||
<entry>Равно</entry>
|
||
<entry>
|
||
Возвращается &true;, если значение переменной <varname>$a</varname>
|
||
после преобразования типов равно
|
||
значению переменной <varname>$b</varname>.
|
||
</entry>
|
||
</row>
|
||
<row>
|
||
<entry>$a === $b</entry>
|
||
<entry>Тождественно равно</entry>
|
||
<entry>
|
||
Возвращается &true;, если значение переменной <varname>$a</varname>
|
||
равно значению переменной <varname>$b</varname> и имеет тот же тип.
|
||
</entry>
|
||
</row>
|
||
<row>
|
||
<entry>$a != $b</entry>
|
||
<entry>Не равно</entry>
|
||
<entry>
|
||
Возвращается &true;, если значение переменной <varname>$a</varname>
|
||
после преобразования типов
|
||
не равно значению переменной <varname>$b</varname>.
|
||
</entry>
|
||
</row>
|
||
<row>
|
||
<entry>$a <> $b</entry>
|
||
<entry>Не равно</entry>
|
||
<entry>
|
||
Возвращается &true;, если значение переменной <varname>$a</varname>
|
||
после преобразования типов
|
||
не равно значению переменной <varname>$b</varname>.
|
||
</entry>
|
||
</row>
|
||
<row>
|
||
<entry>$a !== $b</entry>
|
||
<entry>Тождественно не равно</entry>
|
||
<entry>
|
||
Возвращается &true;, если значение переменной <varname>$a</varname>
|
||
не равно значению переменной <varname>$b</varname>
|
||
или они разных типов.
|
||
</entry>
|
||
</row>
|
||
<row>
|
||
<entry>$a < $b</entry>
|
||
<entry>Меньше</entry>
|
||
<entry>
|
||
Возвращается &true;, если значение переменной <varname>$a</varname>
|
||
строго меньше значения переменной <varname>$b</varname>.
|
||
</entry>
|
||
</row>
|
||
<row>
|
||
<entry>$a > $b</entry>
|
||
<entry>Больше</entry>
|
||
<entry>
|
||
Возвращается &true;, если значение переменной <varname>$a</varname>
|
||
строго больше значения переменной <varname>$b</varname>.
|
||
</entry>
|
||
</row>
|
||
<row>
|
||
<entry>$a <= $b</entry>
|
||
<entry>Меньше или равно</entry>
|
||
<entry>
|
||
Возвращается &true;, если значение переменной <varname>$a</varname>
|
||
меньше или равно значению переменной <varname>$b</varname>.
|
||
</entry>
|
||
</row>
|
||
<row>
|
||
<entry>$a >= $b</entry>
|
||
<entry>Больше или равно</entry>
|
||
<entry>
|
||
Возвращается &true;, если значение переменной <varname>$a</varname>
|
||
больше или равно значению переменной <varname>$b</varname>.
|
||
</entry>
|
||
</row>
|
||
<row>
|
||
<entry>$a <=> $b</entry>
|
||
<entry>Космический корабль (spaceship)</entry>
|
||
<entry>
|
||
Целое число (<type>int</type>) меньше, больше или равное нулю, когда
|
||
значение переменной <varname>$a</varname> меньше, больше или равно
|
||
значению переменной <varname>$b</varname>.
|
||
</entry>
|
||
</row>
|
||
</tbody>
|
||
</tgroup>
|
||
</table>
|
||
<para>
|
||
Если оба операнда —
|
||
<link linkend="language.types.numeric-strings">строки, содержащие числа</link>,
|
||
или один операнд — число, а другой — <link linkend="language.types.numeric-strings">строка, содержащая числа</link>,
|
||
то сравнение выполняется численно.
|
||
Эти правила также справедливы для оператора <link linkend="control-structures.switch">switch</link>.
|
||
Тип не преобразовывается при сравнениях вида
|
||
<literal>===</literal> или <literal>!==</literal>, поскольку это включает сравнение
|
||
типа, а также значения.
|
||
</para>
|
||
<warning>
|
||
<para>
|
||
До PHP 8.0.0, если строка (<type>string</type>) сравнивалась с числом
|
||
или строкой, содержащей число, то строка (<type>string</type>) преобразовывалась
|
||
в число перед выполнением сравнения. Это могло привести к неожиданным
|
||
результатам, что можно увидеть на следующем примере:
|
||
<informalexample>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?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;
|
||
}
|
||
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs.7;
|
||
<screen>
|
||
<![CDATA[
|
||
bool(true)
|
||
bool(true)
|
||
bool(true)
|
||
bool(true)
|
||
0
|
||
]]>
|
||
</screen>
|
||
&example.outputs.8;
|
||
<screen>
|
||
<![CDATA[
|
||
bool(false)
|
||
bool(true)
|
||
bool(true)
|
||
bool(true)
|
||
a
|
||
]]></screen>
|
||
</informalexample>
|
||
</para>
|
||
</warning>
|
||
<para>
|
||
<informalexample>
|
||
<programlisting role="php"><![CDATA[
|
||
<?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
|
||
?>
|
||
]]>
|
||
|
||
</programlisting>
|
||
</informalexample>
|
||
</para>
|
||
|
||
<para>
|
||
Для различных типов сравнение происходит в соответствии со следующей
|
||
таблицей (по порядку).
|
||
</para>
|
||
<table xml:id="language.operators.comparison.types">
|
||
<title>Сравнение типов</title>
|
||
<tgroup cols="3">
|
||
<thead>
|
||
<row>
|
||
<entry>Тип операнда 1</entry>
|
||
<entry>Тип операнда 2</entry>
|
||
<entry>Результат</entry>
|
||
</row>
|
||
</thead>
|
||
<tbody>
|
||
<row>
|
||
<entry>
|
||
<type>null</type> или <type>string</type>
|
||
</entry>
|
||
<entry>
|
||
<type>string</type>
|
||
</entry>
|
||
<entry>&null; преобразуется в пустую строку (""), числовое или лексическое сравнение</entry>
|
||
</row>
|
||
<row>
|
||
<entry>
|
||
<type>bool</type> или <type>null</type>
|
||
</entry>
|
||
<entry>что угодно</entry>
|
||
<entry>Преобразуется в <type>bool</type>, &false; < &true;</entry>
|
||
</row>
|
||
<row>
|
||
<entry>
|
||
<type>object</type>
|
||
</entry>
|
||
<entry>
|
||
<type>object</type>
|
||
</entry>
|
||
<entry>
|
||
Встроенные классы могут определять свои правила сравнения,
|
||
объекты разных классов не сравниваются,
|
||
про сравнение объектов одного класса рассказано в разделе «<link linkend="language.oop5.object-comparison">Сравнение объекта</link>»
|
||
</entry>
|
||
</row>
|
||
<row>
|
||
<entry>
|
||
<type>string</type>, <type>resource</type>, <type>int</type> или <type>float</type>
|
||
</entry>
|
||
<entry>
|
||
<type>string</type>, <type>resource</type>, <type>int</type> или <type>float</type>
|
||
</entry>
|
||
<entry>Строки и ресурсы переводятся в числа, обычная математика</entry>
|
||
</row>
|
||
<row>
|
||
<entry>
|
||
<type>array</type>
|
||
</entry>
|
||
<entry>
|
||
<type>array</type>
|
||
</entry>
|
||
<entry>
|
||
Массив с меньшим числом элементов меньше,
|
||
если ключ из первого массива не найден во втором массиве —
|
||
массивы не могут сравниваться, иначе идёт сравнение
|
||
значений (смотрите пример ниже)
|
||
</entry>
|
||
</row>
|
||
<row>
|
||
<entry>
|
||
<type>array</type>
|
||
</entry>
|
||
<entry>что угодно</entry>
|
||
<entry>Тип <type>array</type> всегда больше</entry>
|
||
</row>
|
||
<row>
|
||
<entry>
|
||
<type>object</type>
|
||
</entry>
|
||
<entry>что угодно</entry>
|
||
<entry>Тип <type>object</type> всегда больше</entry>
|
||
</row>
|
||
</tbody>
|
||
</tgroup>
|
||
</table>
|
||
|
||
<para>
|
||
<example>
|
||
<title>Сравнение boolean/null</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?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
|
||
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
|
||
<para>
|
||
<example>
|
||
<title>Алгоритм сравнения обычных массивов</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?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
|
||
}
|
||
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
|
||
<warning>
|
||
<title>Сравнение чисел с плавающей точкой</title>
|
||
|
||
<para>
|
||
По причинам, связанным со способом внутреннего представления чисел с плавающей точкой (<type>float</type>),
|
||
не нужно проверять два числа с плавающей точкой (<type>float</type>) на равенство.
|
||
</para>
|
||
|
||
<para>
|
||
Подробнее об этом можно узнать в документации по типу <type>float</type>.
|
||
</para>
|
||
</warning>
|
||
|
||
<note>
|
||
<simpara>
|
||
Когда пишут код, помнят, что жонглирование типами в PHP
|
||
не всегда даёт предсказуемый результат при сравнении значений разных типов,
|
||
особенно при сравнении целых чисел (&integer;) с логическими значениями (&boolean;)
|
||
или целых чисел (&integer;) со строками (&string;).
|
||
Поэтому лучше пользоваться операторами <literal>===</literal> и <literal>!==</literal>,
|
||
а не <literal>==</literal> и <literal>!=</literal>.
|
||
</simpara>
|
||
</note>
|
||
|
||
<sect2 xml:id="language.operators.comparison.incomparable">
|
||
<title>Несравнимые значение</title>
|
||
<simpara>
|
||
Хотя тождественные сравнения (<literal>===</literal> и <literal>!==</literal>)
|
||
можно применять к произвольным значениям,
|
||
другие операторы сравнения лучше применять только к сравнимым значениям.
|
||
Результат сравнения несравнимых значений не определён и на него не нужно полагаться.
|
||
</simpara>
|
||
</sect2>
|
||
|
||
<sect2 role="seealso">
|
||
&reftitle.seealso;
|
||
<para>
|
||
<simplelist>
|
||
<member><function>strcasecmp</function></member>
|
||
<member><function>strcmp</function></member>
|
||
<member><link linkend="language.operators.array">Операторы, работающие с массивами</link></member>
|
||
<member><link linkend="language.types">Типы</link></member>
|
||
</simplelist>
|
||
</para>
|
||
</sect2>
|
||
|
||
<sect2 xml:id="language.operators.comparison.ternary">
|
||
<title>Тернарный оператор</title>
|
||
<para>
|
||
Ещё один условный оператор — тернарный оператор «?:».
|
||
<example>
|
||
<title>Присваивание значения по умолчанию</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
// Пример выражения с тернарным оператором
|
||
$action = (empty($_POST['action'])) ? 'default' : $_POST['action'];
|
||
|
||
// Код выше аналогичен блоку с конструкциями if/else
|
||
if (empty($_POST['action'])) {
|
||
$action = 'default';
|
||
} else {
|
||
$action = $_POST['action'];
|
||
}
|
||
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
Выражение <literal>(expr1) ? (expr2) : (expr3)</literal>
|
||
интерпретируется как <replaceable>expr2</replaceable>, если
|
||
<replaceable>expr1</replaceable> равно &true;, или как
|
||
<replaceable>expr3</replaceable>, если
|
||
<replaceable>expr1</replaceable> равно &false;.
|
||
</para>
|
||
<para>
|
||
Можно не писать среднюю часть тернарного оператора.
|
||
Выражение <literal>expr1 ?: expr3</literal> оценивается
|
||
как результат выражения <replaceable>expr1</replaceable>,
|
||
если оно оценивается как &true;,
|
||
иначе как результат выражения <replaceable>expr3</replaceable>.
|
||
Выражение <replaceable>expr1</replaceable> оценивается только один раз.
|
||
</para>
|
||
<note>
|
||
<simpara>
|
||
Обратите внимание, что тернарный оператор — это выражение,
|
||
и он оценивается не как переменная, а как результат выражения.
|
||
Это важно, если нужно вернуть переменную по ссылке.
|
||
Выражение <literal>return $var == 42 ? $a : $b;</literal> не будет
|
||
работать в функции, возвращающей значение по ссылке, а в более поздних
|
||
версиях PHP также будет выдано предупреждение.
|
||
</simpara>
|
||
</note>
|
||
<note>
|
||
<para>
|
||
Рекомендовано избегать «нагромождения» тернарных выражений.
|
||
Поведение PHP при указании более чем одного тернарного оператора без скобок
|
||
в одном выражении неочевидно в сравнении с другими языками.
|
||
Впрямь, до PHP 8.0.0 троичные выражения оценивались как левоассоциативные,
|
||
а не правоассоциативные, как в большей части других языков программирования.
|
||
Опора на левую ассоциативность устарела начиная с PHP 7.4.0.
|
||
Начиная с PHP 8.0.0 тернарный оператор неассоциативен.
|
||
<example>
|
||
<title>Неочевидное поведение тернарного оператора</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
// кажется, что следующий код выведет «true»
|
||
echo (true ? 'true' : false ? 't' : 'f');
|
||
|
||
// однако он выводит «t» до PHP 8.0.0
|
||
// это потому, что тернарные выражения левоассоциативны
|
||
|
||
// следующая запись — более очевидная версия того же кода, который показан выше
|
||
echo ((true ? 'true' : false) ? 't' : 'f');
|
||
|
||
// здесь видно, что первое выражение оценивается как строковое «true», которое
|
||
// оценивается как логическое (bool) true, поэтому возвращает истинную ветвь
|
||
// второго тернарного выражения.
|
||
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
</note>
|
||
<note>
|
||
<para>
|
||
Цепочка коротких тернарных операторов (<literal>?:</literal>), однако, стабильна и ведёт себя обоснованно.
|
||
Она будет оценивать первый аргумент, который оценивается как не ложное значение.
|
||
Обратите внимание, что неопределённые значения все равно вызовут предупреждение.
|
||
<example>
|
||
<title>Цепочка коротких тернарных операторов</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?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
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
</note>
|
||
</sect2>
|
||
|
||
<sect2 xml:id="language.operators.comparison.coalesce">
|
||
<title>Оператор объединения с null</title>
|
||
<para>
|
||
Другой полезный сокращённый оператор — это оператор объединения с NULL — «??» (null coalescing).
|
||
<example>
|
||
<title>Присваивание значения по умолчанию</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
// Пример работы с оператором нулевого слияния
|
||
$action = $_POST['action'] ?? 'default';
|
||
|
||
// Пример выше аналогичен этому выражению с if/else
|
||
if (isset($_POST['action'])) {
|
||
$action = $_POST['action'];
|
||
} else {
|
||
$action = 'default';
|
||
}
|
||
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
Выражение <literal>(expr1) ?? (expr2)</literal> вычисляется так:
|
||
<replaceable>expr2</replaceable>, если <replaceable>expr1</replaceable> равно
|
||
&null;, иначе <replaceable>expr1</replaceable>.
|
||
</para>
|
||
<para>
|
||
Этот оператор не вызывает предупреждения или ошибки, если левый операнд
|
||
не существует, точно как языковая конструкция <function>isset</function>.
|
||
Это очень полезно для ключей массива.
|
||
</para>
|
||
<note>
|
||
<simpara>
|
||
Обратите внимание, оператор объединения с NULL — это выражение,
|
||
и он оценивается не как переменная, а как результат вычисления выражения.
|
||
Это важно, если нужно
|
||
вернуть значение по ссылке. Выражение <literal>return $foo ?? $bar;</literal> в
|
||
функции, возвращающей ссылку, будет не работать, а выводить предупреждение.
|
||
</simpara>
|
||
</note>
|
||
<note>
|
||
<para>
|
||
У оператора объединения с NULL низкий приоритет. То есть при смешивании его с другими операторами
|
||
(например, с операторами конкатенации строк или арифметическими операторами), скорее всего, потребуются круглые скобки.
|
||
</para>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
// Вызывает предупреждение о том, что $name не определено.
|
||
print 'Mr. ' . $name ?? 'Anonymous';
|
||
|
||
// Выведет "Mr. Anonymous"
|
||
print 'Mr. ' . ($name ?? 'Anonymous');
|
||
|
||
]]>
|
||
</programlisting>
|
||
</note>
|
||
<note>
|
||
<para>
|
||
Обратите внимание, оператор объединения с NULL разрешает простую вложенность:
|
||
<example>
|
||
<title>Вложенный оператор null coalescing</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
$foo = null;
|
||
$bar = null;
|
||
$baz = 1;
|
||
$qux = 2;
|
||
|
||
echo $foo ?? $bar ?? $baz ?? $qux; // выведет 1
|
||
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
</note>
|
||
</sect2>
|
||
</sect1>
|
||
<!-- Keep this comment at the end of the file
|
||
Local variables:
|
||
mode: sgml
|
||
sgml-omittag:t
|
||
sgml-shorttag:t
|
||
sgml-minimize-attributes:nil
|
||
sgml-always-quote-attributes:t
|
||
sgml-indent-step:1
|
||
sgml-indent-data:t
|
||
indent-tabs-mode:nil
|
||
sgml-parent-document:nil
|
||
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
|
||
sgml-exposed-tags:nil
|
||
sgml-local-catalogs:nil
|
||
sgml-local-ecat-files:nil
|
||
End:
|
||
vim600: syn=xml fen fdm=syntax fdl=2 si
|
||
vim: et tw=78 syn=sgml
|
||
vi: ts=1 sw=1
|
||
-->
|