PHP słynie z żonglowania typami. Muszę przyznać, że intryguje mnie to i ciężko mi jest znaleźć podstawowe logiczne / fundamentalne rzeczy w porównaniach.
Na przykład: Jeśli $a > $b
jest prawdą i $b > $c
jest prawdą, czy musi to oznaczać, że zawsze$a > $c
jest prawdą?
Kierując się podstawową logiką, powiedziałbym tak, ale jestem zdziwiony, że nie ufam w tym PHP. Może ktoś może podać przykład, gdzie tak nie jest?
Zastanawiam się również z operatorami ściśle mniejszymi niż i ścisłymi większymi niż (ponieważ ich znaczenie jest opisane jako ścisłe, które znałem tylko w przeszłości z porównań równości), czy ma znaczenie, czy lewy i prawy operand są zamienione z wartości ściśle nierówne:
# Precondition:
if ($a === $b) {
throw new Exception(
'Both are strictly equal - can not compare strictly for greater or smaller'
);
}
($a > $b) !== ($b > $a)
W przypadku większości kombinacji porównania typów te większe / mniejsze operatory porównania nie są udokumentowane, więc przeczytanie instrukcji nie było w tym przypadku zbyt pomocne.
źródło
($a > $b) !== ($b < $a)
?Odpowiedzi:
Operatory porównania PHP odbiegają od definicji komputerowo-naukowych na kilka sposobów:
Aby relacja równoważności
==
mogła być utworzona, musi być zwrotna, symetryczna i przechodnia:==
Operator PHP nie jest zwrotny , tj.$a == $a
Nie zawsze jest prawdziwy:Uwaga: Fakt, że każde porównanie
NAN
jest zawszefalse
związane z PHP. Jest to wymagane przez standard IEEE 754 dla arytmetyki zmiennoprzecinkowej ( więcej informacji ).==
Operator PHP jest symetryczny , tj.$a == $b
I$b == $a
zawsze jest taki sam.PHP
==
operator jest nie przechodni , czyli od$a == $b
i$b == $c
ma nie następująco$a == $c
:Aby stanowić porządek częściowy
<=
/>=
musi być zwrotny, antysymetryczny i przechodni:<=
Operator PHP nie jest zwrotny , tj.$a <= $a
Nie zawsze jest prawdziwy (przykład taki sam jak for==
).<=
Operator PHP nie jest anty-symetryczny , tj. Z$a <= $b
i$b <= $a
nie wynika$a == $b
:<=
Operator PHP nie jest przechodni , tj. Od$a <= $b
i$b <= $c
nie następuje$a <= $c
(przykład taki sam jak for==
).Dodatkowo:
<=
operator PHP nie jest całkowity , tj. Oba$a <= $b
i$b <= $a
mogą być fałszywe:Aby stanowić ścisły porządek cząstkowy
<
/>
musi być nieodwracalny, asymetryczny i przechodni:<
Operator PHP jest nierefleksyjny , tj.$a < $a
Nigdy nie jest prawdziwy. Zauważ, że jest to prawdą tylko od PHP 5.4 . WcześniejINF < INF
oceniane dotrue
.<
Operator PHP nie jest asymetryczny , tj.$a < $b
From nie następuje!($b < $a)
(przykład taki sam jak w przypadku<=
braku anty-symetrii).<
Operator PHP nie jest przechodni , tj. Od$a < $b
i$b < $c
nie następuje$a < $c
:Dodatkowo:
<
operator PHP nie jest trychotomiczny , tj. All of$a < $b
,$b < $a
i$a == $b
może być fałszywy (przykład taki sam, jak w przypadku<=
braku sumy).Extra: PHP
<
operator może być okrągły , to znaczy, że jest to możliwe$a < $b
,$b < $c
i$c < $a
:Uwaga: Powyższy przykład generuje powiadomienie „Nie można przekonwertować obiektu klasy stdClass na podwójny”.
Możesz znaleźć kilka ładnych wykresów dla operatorów porównania PHP na stronie PHP Sadness 52 - Operatory porównania .
Jako ostatnią nutę, chcę podkreślić, że istnieją dwie równości że PHP ma gwarancji (w przeciwieństwie do niemal wszystkiego innego). Te dwa zawsze się trzymają, po prostu dlatego, że kompilator redukuje jedno do drugiego:
źródło
($a > $b) and ($b > $c)
przypadku,$a > $c
mimo że dokumentacja mówi, że operatorzy<
/>
mówią, że są ścisłe ?$a == $b
to to samo co(type) $a === (type) $b
. Prostym tego przykładem jest to"15" == "0xf"
, ale(int) "15" !== (int) "0xf"
. I zarówno porównanie, jak i reguły castingu w PHP są totalnie szalone ^^(int)"0xf"
ewaluuje do liczby całkowitej0
, więc oczywiście0 !== 15
. Porównanie w tym przykładzie zachowuje się dokładnie tak, jak oczekiwano. To casting jest mylący. Przyznaję,(INF < INF) === true
był to prawdziwy problem z porównaniem, ale był to szczególny przypadek i został rozwiązany, jak wskazałeś. Świetna odpowiedź… +1W PHP nie ma ściśle identycznych operatorów porównania (
>==
lub<==
) (przynajmniej od PHP 5.6.14) , ale istnieje kilka sposobów na wymuszenie ścisłego sprawdzenia typu przed sprawdzeniem Większy / Dolny:if (gettype($a) === gettype($b))
if ((string)$a === (string)$b)
if (($a . '') === ($b . ''))
Zwróć uwagę, że:
INF
iNAN
są typufloat
underieee754e
jest zawsze typufloat
i nigdy,integer
nawet jeśli liczba jest małaPHP_INT_MAX
są automatycznie konwertowane nafloat
INF
wartośćNULL
0
są konwertowane z ósemkowego na dziesiętny (zgodnie z konwencją)0
na liczbę całkowitą usuwa początkowe0
Lista egzotycznych porównań:
Równe, ale nie identyczne:
Niższy i większy w tym samym czasie?
Równe I identyczne:
Mniejsze lub większe:
$a > $b > $c
Zagadka, gdy:$a
nie jest większe niż$c
.Zabawne porównanie strun: „Dama”
>
„Król”>
„Walet”>
„As”Sprawdź również tabele porównawcze typów PHP obejmujące pary:
isset()
iis_null()
if()
iempty()
==
vs.===
Sprawdź różnice między wersjami PHP dostępnymi pod adresem. http://3v4l.org/MAfDu .
źródło
if ( (string)$a===(string)$b )
ale czy to nie jest dokładnie to samo coif ( (string)$a==(string)$b )
?(string)1==(string)'01'
->bool(true)
i dla typu juggle(1 . '')=='01'
->bool(true)
nie dokładnie to samo, co w===
przypadkubool(false)
obu kontINFINITY is equal to INFINITY which is mathematically incorrect!
jest zdecydowanie dyskusyjnym stwierdzeniem. Zauważ również, żeNaN
zgodnie z konwencją jest to nie większe niż, mniejsze lub równe czegokolwiek w jakimkolwiek znanym mi języku programowania.Po poprawieniu drugiej części pytania, odpowiedź na tę część pozostawiam pozostałym. Chcę tylko udzielić najbardziej zaskakującej odpowiedzi na pierwszą część twojego pytania, tj. Czy istnieje przykład nieprzechodni operatorów
<
i>
. Tutaj jest.To wszystko
true
:Gdyby
<
była przechodnia ($a < $b
∧$b < $c
⇒$a < $c
), ostatnia linia byłabyale PHP stara się być uprzejmy (?!) i interpretować łańcuchy jako liczby, kiedy tylko może.
Okazuje się, że ze względu na powyższą nieprzechodność,
sort()
może sortować te same elementy w różnej kolejności w zależności od ich kolejności wejściowej, nawet gdy nie ma dwóch elementów==
(i żaden element nie jest NAN). Zwróciłem na to uwagę w komentarzu do sort () , którego istotą jest:źródło
sort()
stół, wybrałem go również ze względu na praktyczne implikacje podczas pisania powiązanego wpisu na blogu The Greatest PHP Value . Jeszcze raz dziękuję za odpowiedź.usort
gdy tylko jest to możliwe?usort($arr, 'strcmp')
. To działa (oczywiście w przypadku stringów), ale najlepiej jest używaćsort($arr, SORT_STRING)
.