W przejętej do utrzymania aplikacji napisanej w PHP zauważyłem, że podczas testowania warunków if() zamiast używania operatorów && i || stosowano and i or. Ponieważ ja zawsze używałem tych pierwszych postanowiłem sprawdzić czym to się różni. Po lekturze dokumentacji i sieci można powiedzieć, że sprawa kręci się wokół dwóch rzeczy: kolejność operatorów (operator precedence) i short-circuit evaluation. To drugie nie wiem jak ładnie przetłumaczyć, ale chodzi o jak najszybsze zakończenie sprawdzania warunków true/false – to znaczy kiedy silnik PHP uzna, że zna już odpowiedź, to nie sprawdza pozostałych warunków.
Ma to miejsce kiedy:
- pierwsza część warunku and zwraca false – bo od razu wiadomo, że cały warunek zwróci false
- pierwsza część warunku or zwraca wartość true – bo od razu wiadomo, że cały warunek zwróci true
Dla przypomnienia krótka powtórka z logiki matematycznej: and zwraca true tylko jeśli oba elementy są true, or zwraca false tylko jeśli oba elementy są false.
A B AND OR 0 0 0 0 0 1 0 1 1 0 0 1 1 1 1 1
Dla zilustrowania zagadnienia posłużę się przykładem
<?php $a = true || false; $b = (true || false); var_dump($a, $b); $c = true or false; $d = (true or false); var_dump($c, $d); $e = false || true; $f = (false || true); var_dump($e, $f); $g = false or true; $h = (false or true); var_dump($g, $h); echo "----------\n"; $A = true && false; $B = (true && false); var_dump($A, $B); $C = true and false; $D = (true and false); var_dump($C, $D); $E = false && true; $F = (false && true); var_dump($E, $F); $G = false and true; $H = (false and true); var_dump($G, $H); ?>
Co zwróci:
bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(false) bool(true) ---------- bool(false) bool(false) bool(true) bool(false) bool(false) bool(false) bool(false) bool(false)
Dlaczego zwracane są takie wartości? Jeszcze krótkie przypomnienie z kolejności operatorów. Z używanych powyżej od najważniejszego:
&&
||
=
and
or
Short-circuit evaluation ma miejsce w przykładach $a, $b, $c, $d, $E, $F.
W przykładach $e, $f, $h, $A, $B, $D, $H PHP musi obliczyć wynik, bo go nie zna na podstawie pierwszego warunku. Pozostają do omówienia przypadki $g, $C i $G. Tu sprawa wygląda inaczej z powodu kolejności operatorów.
$g = false or true zwraca false, ponieważ najpierw do zmiennej $g jest przypisywana wartość false, a następnie następuje operacja or true, która niczego niczemu nie przypisuje. Taka instrukcja to jakby złożenie dwóch poleceń:
$g = false;
$g or true;
Drugie z nich po prostu robi operację porównania, która zwraca true, ale nie przypisuje już tego zmiennej $g.
Tak samo w pozostałych przypadkach:
$C = true and false zwraca true:
$C = true;
$C and false;
$G = false and true zwraca false:
$G = false;
$G and true;
Żeby jeszcze bardziej unaocznić działanie short-circuit evaluation taki przykład:
if(true || $n = 1) {
echo $n;
}
Zmienna $n nie pojawi się na ekranie, ponieważ silnik PHP uznał, że warunek if zwraca true i reszty instrukcji już nie wykonuje.
No, to na koniec jeszcze wnioski. Jeśli nie chcesz się zamotać w warunkach – stosuj nawiasy. Jeśli chcesz przyspieszyć działanie warunków – w przypadkach or dawaj warunki zwracające true jak najbliżej lewej strony (np. 1 or 0). W przypadku and najbliżej lewej strony dawaj warunki false (np. 0 and 1).