PHP известен своим жужжанием типа. Я должен признать, что это меня озадачивает, и мне сложно найти основные логические / фундаментальные вещи в сравнении.
Например: если $a > $b
истинно, а $b > $c
– true, значит, оно означает, что $a > $c
всегда истинно?
Следуя основной логике, я бы сказал, что да, но я озадачен тем, что в действительности я не доверяю PHP. Может быть, кто-то может привести пример, где это не так?
Также мне интересно со строгими меньшими и строгими операторами большего размера (так как их значение описывается как строгое, о котором я знал только в прошлом из сравнений равенства), если имеет значение, если левый и правый операнды меняются местами строго неравные значения:
# Precondition: if ($a === $b) { throw new Exception( 'Both are strictly equal - can not compare strictly for greater or smaller' ); } ($a > $b) !== ($b > $a)
Для большинства комбинаций сравнения типов эти более крупные / меньшие операторы сравнения не документируются, поэтому чтение этого руководства в этом случае не очень полезно.
Операторы сравнения PHP отклоняются от компьютерно-научных определений несколькими способами:
Чтобы составить отношение эквивалентности ==
, должно быть рефлексивным, симметричным и транзитивным:
Оператор PHP ==
не рефлексивен , то есть $a == $a
не всегда верен:
var_dump(NAN == NAN); // bool(false)
Примечание. Тот факт, что любое сравнение с NAN
всегда является false
, не является специфичным для PHP. Это предусмотрено стандартом IEEE 754 для арифметики с плавающей точкой ( подробнее ).
Оператор PHP ==
является симметричным , т.е. $a == $b
и $b == $a
всегда одинаковы.
Оператор PHP ==
не является транзитивным , т. Е. Из $a == $b
и $b == $c
не следует $a == $c
:
var_dump(true == "a"); // bool(true) var_dump("a" == 0); // bool(true) var_dump(true == 0); // bool(false)
Чтобы составить частичный порядок <=
/ >=
должен быть рефлексивным, антисимметричным и транзитивным:
PHP <=
оператор не рефлексивен , т. Е. $a <= $a
не всегда истинно (пример такой же, как для ==
).
PHP <=
оператор не является антисимметричным , т. Е. Из $a <= $b
и $b <= $a
не следует $a == $b
:
var_dump(NAN <= "foo"); // bool(true) var_dump("foo" <= NAN); // bool(true) var_dump(NAN == "foo"); // bool(false)
PHP <=
оператор не является транзитивным , т. Е. Из $a <= $b
и $b <= $c
не следует $a <= $c
(пример такой же, как для ==
).
Дополнительно: PHP <=
оператор не является тотальным , то есть оба значения $a <= $b
и $b <= $a
могут быть ложными:
var_dump(new stdClass <= new DateTime); // bool(false) var_dump(new DateTime <= new stdClass); // bool(false)
Для того чтобы составить строгий частичный порядок <
/ >
должен быть нерефлексивным, асимметричным и транзитивным:
Оператор PHP <
оператор является непереходным , т. Е. $a < $a
A $a < $a
никогда не является истинным. Обратите внимание, что это верно только с PHP 5.4 . Ранее INF < INF
оценивался как true
.
Оператор PHP не является асимметричным , т. Е. Из $a < $b
не следует !($b < $a)
(Пример такой же, как для <=
несимметричный).
Оператор PHP <
operator не является транзитивным , т. Е. Из $a < $b
и $b < $c
не следует $a < $c
:
var_dump(-INF < 0); // bool(true) var_dump(0 < TRUE); // bool(true) var_dump(-INF < TRUE); // bool(false)
Дополнительно: PHP <
operator не является трихотомным , то есть все $a < $b
, $b < $a
и $a == $b
могут быть ложными (пример такой же, как для <=
не является полным).
Дополнительно: PHP <
оператор может быть круговым , т. Е. Возможно, что $a < $b
, $b < $c
и $c < $a
:
var_dump(INF < []); // bool(true) var_dump([] < new stdClass); // bool(true) var_dump(new stdClass < INF); // bool(true)
Примечание. В приведенном выше примере выдается сообщение об ошибке «Объект класса stdClass не может быть преобразован в двойное».
Вы можете найти несколько хороших графиков для операторов сравнения PHP на PHP Sadness 52 – Операторы сравнения .
Как последнее примечание, я хочу отметить, что есть два равенства, которые PHP действительно гарантирует (в отличие от всего остального). Эти два всегда сохраняются, просто потому, что компилятор сводит один к другому:
($a > $b) == ($b < $a) ($a >= $b) == ($b <= $a)
В PHP нет строгих идентичных операторов сравнения ( >==
или <==
) в PHP (по крайней мере , по PHP 5.6.14) , но есть несколько способов обеспечить строгую проверку типа перед проверкой Greater / Lower:
if (gettype($a) === gettype($b))
if ((string)$a === (string)$b)
if (($a . '') === ($b . ''))
Обратите внимание:
INF
и NAN
имеют тип float
под ieee754 e
всегда имеет тип float
и никогда не является integer
даже если число мало PHP_INT_MAX
автоматически преобразуются в float
INF
NULL
0
, преобразуются из восьмеричного в десятичное (по соглашению) 0
до целого, переводит начало 0
Список некоторых экзотических сравнений:
Очень странно: $ VS. $ b $ a> $ b $ a <$ b $ a <= $ b $ a> = $ b $ a == $ b $ a === $ b float (NAN) float (-INF) false false false false false false false float (NAN) float (0) false false false false false false false float (NAN) float (1) false false false false false false false float (NAN) float (INF) false false false false false false false float (NAN) float (NAN) false false false false false false float (NAN) int (-1) false false false false false false float (NAN) int (0) false false false false false false float (NAN) int (1) false false false false false false
Равный, но не идентичный:
$ VS. $ b $ a> $ b $ a <$ b $ a <= $ b $ a> = $ b $ a == $ b $ a === $ b
NULL (NULL) array () false false true true true true false NULL (NULL) bool (false) false false true true true true false NULL (NULL) float (0) false false true true true false NULL (NULL) int (0) false false true true true true false NULL (NULL) str ('') false false true true true false array () bool (false) false false true true true true false bool (false) float (0) false false true true true false bool (false) int (0) false false true true true false str ('') bool (false) false false true true true true false bool (false) str ('0') false false true true true true false float (-INF) bool (true) false false true true true false false bool (true) float (1) false false true true true true false float (INF) bool (true) false false true true true true false float (NAN) bool (true) false false true true true true false bool (true) int (-1) false false true true true false false bool (true) int (1) false false true true true true false bool (true) str ("\ 0") false false true true true false false bool (true) str ('+') false false true true true false false bool (true) str ('-') false false true true true true false bool (true) str ('01 ') false false true true true false false bool (true) str ('1') false false true true true false false bool (true) str ('false') false false true true true true false str ('text') bool (true) false false true true true true false str ('true') bool (true) false false true true true true false int (0) float (0) false false true true true false false str ("\ 0") float (0) false false true true true false false str ('') float (0) false false true true true false false str ('+') float (0) false false true true true false false str ('-') float (0) false false true true true true false str ('0') float (0) false false true true true false false str ('false') float (0) false false true true true false false str ('text') float (0) false false true true true true false str ('true') float (0) false false true true true true false int (1) float (1) false false true true true true false float (1) str ('01 ') false false true true true true false float (1) str ('1') false false true true true false false str ("\ 0") int (0) false false true true true false false str ('') int (0) false false true true true true false str ('+') int (0) false false true true true false false str ('-') int (0) false false true true true false false int (0) str ('0') false false true true true true false str ('false') int (0) false false true true true false false str ('text') int (0) false false true true true false false str ('true') int (0) false false true true true true false int (1) str ('01 ') false false true true true true false int (1) str ('1') false false true true true false str ('1') str ('01 ') false false true true true true false
Нижний и Большой одновременно?
$ VS. $ b $ a> $ b $ a <$ b $ a <= $ b $ a> = $ b $ a == $ b $ a === $ b float (NAN) str ("\ 0") true true true true false false float (NAN) str ('') true true true true false false float (NAN) str ('+') true true true true false false false float (NAN) str ('-') true true true true false false float (NAN) str ('0') true true true true false false float (NAN) str ('01 ') true true true true false false false float (NAN) str ('1') true true true true false false false float (NAN) str ('false') true true true true false false false float (NAN) str ('text') true true true true false false false float (NAN) str ('true') true true true true false false
Равно и тождественно:
$ VS. $ b $ a> $ b $ a <$ b $ a <= $ b $ a> = $ b $ a == $ b $ a === $ b NULL (NULL) NULL (NULL) false false true true true true true float (-INF) float (-INF) false false true true true true true float (INF) float (INF) false false true true true true true
Нижний или Большой:
$ VS. $ b $ a> $ b $ a <$ b $ a <= $ b $ a> = $ b $ a == $ b $ a === $ b
NULL (NULL) bool (true) false true true false false false false float (-INF) NULL (NULL) true false false true false false false NULL (NULL) float (1) false true true false false false false float (INF) NULL (NULL) true false false true false false false float (NAN) NULL (NULL) true false false true false false false NULL (NULL) int (-1) false true true false false false false NULL (NULL) int (1) false true true false false false false NULL (NULL) str ("\ 0") false true true false false false false NULL (NULL) str ('+') false true true false false false false NULL (NULL) str ('-') false true true false false false false NULL (NULL) str ('0') false true true false false false false NULL (NULL) str ('01 ') false true true false false false false NULL (NULL) str ('1') false true true false false false false NULL (NULL) str ('false') false true true false false false false NULL (NULL) str ('text') false true true false false false false NULL (NULL) str ('true') false true true false false false false array () bool (true) false true true false false false false float (-INF) array () false true true false false false false array () float (0) true false false true false false false array () float (1) true false false true false false false float (INF) array () false true true false false false false float (NAN) array () false true true false false false false array () int (-1) true false false true false false false array () int (0) true false false true false false false array () int (1) true false false true false false false array () str ("\ 0") true false false true false false false str ('') array () false true true false false false false array () str ('+') true false false true false false false array () str ('-') true false false true false false false array () str ('0') true false false true false false false array () str ('01 ') true false false true false false false array () str ('1') true false false true false false false array () str ('false') true false false true false false false array () str ('text') true false false true false false false array () str ('true') true false false true false false false bool (true) bool (false) true false false true false false false float (-INF) bool (false) true false false true false false false float (1) bool (false) true false false true false false false float (INF) bool (false) true false false true false false false float (NAN) bool (false) true false false true false false false bool (false) int (-1) false true true false false false false int (1) bool (false) true false false true false false false bool (false) str ("\ 0") false true true false false false false bool (false) str ('+') false true true false false false false bool (false) str ('-') false true true false false false false bool (false) str ('01 ') false true true false false false false str ('1') bool (false) true false false true false false false bool (false) str ('false') false true true false false false false str ('text') bool (false) true false false true false false false str ('true') bool (false) true false false true false false false bool (true) float (0) true false false true false false false bool (true) int (0) true false false true false false false str ('') bool (true) false true true false false false false bool (true) str ('0') true false false true false false false float (-INF) float (0) false true true false false false false float (-INF) float (1) false true true false false false false float (INF) float (-INF) true false false true false false false float (-INF) int (-1) false true true false false false false float (-INF) int (0) false true true false false false false float (-INF) int (1) false true true false false false false float (-INF) str ("\ 0") false true true false false false false float (-INF) str ('') false true true false false false float (-INF) str ('+') false true true false false false false float (-INF) str ('-') false true true false false false false float (-INF) str ('0') false true true false false false false float (-INF) str ('01 ') false true true false false false false float (-INF) str ('1') false true true false false false false float (-INF) str ('false') false true true false false false false float (-INF) str ('text') false true true false false false false float (-INF) str ('true') false true true false false false false float (1) float (0) true false false true false false false float (INF) float (0) true false false true false false false float (0) int (-1) true false false true false false false int (1) float (0) true false false true false false false float (0) str ('01 ') false true true false false false false str ('1') float (0) true false false true false false false float (INF) float (1) true false false true false false false float (1) int (-1) true false false true false false false float (1) int (0) true false false true false false false float (1) str ("\ 0") true false false true false false false str ('') float (1) false true true false false false false float (1) str ('+') true false false true false false false float (1) str ('-') true false false true false false false float (1) str ('0') true false false true false false false float (1) str ('false') true false false true false false false str ('text') float (1) false true true false false false false str ('true') float (1) false true true false false false false float (INF) int (-1) true false false true false false false float (INF) int (0) true false false true false false false float (INF) int (1) true false false true false false false float (INF) str ("\ 0") true false false true false false false float (INF) str ('') true false false true false false false float (INF) str ('+') true false false true false false false float (INF) str ('-') true false false true false false false float (INF) str ('0') true false false true false false false float (INF) str ('01 ') true false false true false false false float (INF) str ('1') true false false true false false false float (INF) str ('false') true false false true false false false float (INF) str ('text') true false false true false false false float (INF) str ('true') true false false true false false false int (0) int (-1) true false false true false false false int (1) int (-1) true false false true false false false str ("\ 0") int (-1) true false false true false false false str ('') int (-1) true false false true false false false str ('+') int (-1) true false false true false false false str ('-') int (-1) true false false true false false false str ('0') int (-1) true false false true false false false int (-1) str ('01 ') false true true false false false false str ('1') int (-1) true false false true false false false str ('false') int (-1) true false false true false false false str ('text') int (-1) true false false true false false false str ('true') int (-1) true false false true false false false int (1) int (0) true false false true false false false int (0) str ('01 ') false true true false false false false str ('1') int (0) true false false true false false false int (1) str ("\ 0") true false false true false false false str ('') int (1) false true true false false false false int (1) str ('+') true false false true false false false int (1) str ('-') true false false true false false false int (1) str ('0') true false false true false false false int (1) str ('false') true false false true false false false str ('text') int (1) false true true false false false false str ('true') int (1) false true true false false false false str ('') str ("\ 0") false true true false false false false str ('+') str ("\ 0") true false false true false false false str ('-') str ("\ 0") true false false true false false false str ("\ 0") str ('0') false true true false false false false str ("\ 0") str ('01 ') false true true false false false false str ('1') str ("\ 0") true false false true false false false str ('false') str ("\ 0") true false false true false false false str ('text') str ("\ 0") true false false true false false false str ('true') str ("\ 0") true false false true false false false str ('') str ('+') false true true false false false false str ('') str ('-') false true true false false false false str ('') str ('0') false true true false false false false str ('') str ('01 ') false true true false false false false str ('') str ('1') false true true false false false str ('') str ('false') false true true false false false false str ('') str ('text') false true true false false false false str ('') str ('true') false true true false false false false str ('-') str ('+') true false false true false false false str ('+') str ('0') false true true false false false false str ('+') str ('01 ') false true true false false false false str ('1') str ('+') true false false true false false false str ('false') str ('+') true false false true false false false str ('text') str ('+') true false false true false false false str ('true') str ('+') true false false true false false false str ('-') str ('0') false true true false false false false str ('-') str ('01 ') false true true false false false false str ('1') str ('-') true false false true false false false str ('false') str ('-') true false false true false false false str ('text') str ('-') true false false true false false false str ('true') str ('-') true false false true false false false str ('0') str ('01 ') false true true false false false false str ('1') str ('0') true false false true false false false str ('false') str ('0') true false false true false false false str ('text') str ('0') true false false true false false false str ('true') str ('0') true false false true false false false str ('false') str ('01 ') true false false true false false false str ('text') str ('01 ') true false false true false false false str ('true') str ('01 ') true false false true false false false str ('1') str ('false') false true true false false false false str ('text') str ('1') true false false true false false false str ('true') str ('1') true false false true false false false str ('text') str ('false') true false false true false false false str ('true') str ('false') true false false true false false false str ('true') str ('text') true false false true false false false
$a > $b > $c
Загадка, когда: $a
не больше $c
.
A & lt;: float (NAN)> str ('a')> str ('') A & lt;: float (NAN)> str ('a')> str ('1') A & lt;: float (NAN)> str ('a')> str ('A') A & lt;: float (NAN)> str ('a')> str ('0') A & lt;: float (NAN)> str ('1')> str ('') A & lt;: float (NAN)> str ('1')> str ('0') A & lt;: float (NAN)> str ('A')> str ('') A & lt;: float (NAN)> str ('A')> str ('1') A & lt;: float (NAN)> str ('A')> str ('0') A & lt;: float (NAN)> str ('0')> str ('') A & lt: str ('')> float (NAN)> str ('a') A & lt: str ('')> float (NAN)> str ('1') A & lt: str ('')> float (NAN)> str ('A') A & lt: str ('')> float (NAN)> str ('0') A & lt: str ('a')> str ('')> float (NAN) A & lt: str ('a')> str ('1')> float (NAN) A & lt: str ('a')> str ('A')> float (NAN) A & lt: str ('a')> str ('0')> float (NAN) A & lt: str ('0')> str ('')> float (NAN) A == C: bool (true)> str ('')> float (NAN) A == C: bool (true)> str ('')> float (-INF) A == C: bool (true)> str ('')> int (-1) A == C: bool (true)> str ('')> float (-1) A == C: bool (true)> array ()> float (NAN) A == C: bool (true)> array ()> float (INF) A == C: bool (true)> array ()> float (-INF) A == C: bool (true)> array ()> str ('a') A == C: bool (true)> array ()> int (1) A == C: bool (true)> array ()> float (1) A == C: bool (true)> array ()> str ('1') A == C: bool (true)> array ()> str ('A') A == C: bool (true)> array ()> int (-1) A == C: bool (true)> array ()> float (-1) A == C: bool (true)> int (0)> float (-INF) A == C: bool (true)> int (0)> int (-1) A == C: bool (true)> int (0)> float (-1) A == C: bool (true)> str ('0')> float (NAN) A == C: bool (true)> str ('0')> float (-INF) A == C: bool (true)> str ('0')> int (-1) A == C: bool (true)> str ('0')> float (-1) A == C: bool (true)> float (0)> float (-INF) A == C: bool (true)> float (0)> int (-1) A == C: bool (true)> float (0)> float (-1) A == C: int (1)> str ('a')> str ('1') A == C: int (1)> str ('A')> str ('1') A == C: float (1)> str ('a')> str ('1') A == C: float (1)> str ('A')> str ('1') A == C: str ('a')> str ('1')> int (0) A == C: str ('a')> str ('1')> float (0) A == C: str ('')> float (-INF)> NULL (NULL) A == C: str ('')> float (-INF)> bool (false) A == C: str ('')> int (-1)> NULL (NULL) A == C: str ('')> int (-1)> bool (false) A == C: str ('')> float (-1)> NULL (NULL) A == C: str ('')> float (-1)> bool (false) A == C: array ()> float (NAN)> NULL (NULL) A == C: array ()> float (NAN)> bool (false) A == C: array ()> float (INF)> NULL (NULL) A == C: array ()> float (INF)> bool (false) A == C: array ()> float (-INF)> NULL (NULL) A == C: array ()> float (-INF)> bool (false) A == C: array ()> str ('a')> NULL (NULL) A == C: array ()> str ('a')> bool (false) A == C: array ()> int (1)> NULL (NULL) A == C: array ()> int (1)> bool (false) A == C: array ()> float (1)> NULL (NULL) A == C: array ()> float (1)> bool (false) A == C: array ()> str ('1')> NULL (NULL) A == C: array ()> str ('1')> bool (false) A == C: array ()> str ('A')> NULL (NULL) A == C: array ()> str ('A')> bool (false) A == C: array ()> str ('0')> NULL (NULL) A == C: array ()> int (-1)> NULL (NULL) A == C: array ()> int (-1)> bool (false) A == C: array ()> float (-1)> NULL (NULL) A == C: array ()> float (-1)> bool (false) A == C: str ('')> float (NAN)> bool (false) A == C: str ('')> float (NAN)> NULL (NULL) A == C: str ('A')> str ('1')> int (0) A == C: str ('A')> str ('1')> float (0) A == C: int (0)> float (-INF)> NULL (NULL) A == C: int (0)> float (-INF)> bool (false) A == C: int (0)> int (-1)> NULL (NULL) A == C: int (0)> int (-1)> bool (false) A == C: int (0)> float (-1)> NULL (NULL) A == C: int (0)> float (-1)> bool (false) A == C: str ('0')> float (NAN)> bool (false) A == C: str ('0')> float (-INF)> bool (false) A == C: str ('0')> int (-1)> bool (false) A == C: str ('0')> float (-1)> bool (false) A == C: float (0)> float (-INF)> NULL (NULL) A == C: float (0)> float (-INF)> bool (false) A == C: float (0)> int (-1)> NULL (NULL) A == C: float (0)> int (-1)> bool (false) A == C: float (0)> float (-1)> NULL (NULL) A == C: float (0)> float (-1)> bool (false) A === C: str ('0')> float (NAN)> str ('0') A === C: str ('')> float (NAN)> str ('') A === C: str ('a')> float (NAN)> str ('a') A === C: str ('1')> float (NAN)> str ('1') A === C: str ('A')> float (NAN)> str ('A')
Fun string сравнения: 'Queen' >
'King' >
'Jack' >
'Ace'
Также проверьте таблицы сравнения типов PHP, охватывающие пары:
isset()
и is_null()
if()
и empty()
==
vs. ===
Проверьте различия между версиями PHP в прямом эфире. http://3v4l.org/MAfDu .
После исправления второй части вашего вопроса я оставляю ответ на эту часть другим. Я просто хочу дать самый удивительный ответ на первую часть вашего вопроса, т. Е. Есть ли пример операторов <
и >
которые непереходны. Вот.
Все это true
:
"10" < "1a" "1a" < "2" "10" > "2"
Если <
были транзитивными ( $a < $b
∧ $b < $c
⇒ $a < $c
), последняя строка была бы
"10" < "2"
но PHP пытается быть добрым (?!) и интерпретировать строки как числа, когда это возможно.
Оказывается, что из-за вышеперечисленной интранзитивности sort()
может сортировать одни и те же элементы в другом порядке в зависимости от их порядка ввода, даже если ни один из двух элементов не равен ==
(и ни один элемент не является NAN). Я указал это в комментарии к sort () , суть которого такова:
sort(array("10", "1a", "2" )) => array("10", "1a", "2" ) sort(array("10", "2", "1a")) => array("1a", "2", "10") sort(array("1a", "10", "2" )) => array("2", "10", "1a") sort(array("1a", "2", "10")) => array("1a", "2", "10") sort(array("2", "10", "1a")) => array("2", "10", "1a") sort(array("2", "1a", "10")) => array("10", "1a", "2" )