Логические операторы
Одно сравнение отвечает на один вопрос. Но часто ответ зависит сразу от двух: есть ли у покупателя карта и набрал ли он покупок больше чем на тысячу.
Вернёмся к кассе. Скидку кассир даёт по правилу «карта есть И чек больше 1000». По другому правилу подарок положен, если «карта есть ИЛИ сегодня праздник». Связки «и», «или», «не» в PHP записывают логическими операторами.
<?php
$hasCard = true;
$sum = 800;
var_dump($hasCard && $sum > 1000); // bool(false)
var_dump($hasCard || $sum > 1000); // bool(true)
var_dump(!$hasCard); // bool(false)Разберём по строкам:
- В
$hasCard && $sum > 1000сравнение800 > 1000даётfalse, и всё выражение ложно: для&&обе стороны должны быть истинны. - В
$hasCard || $sum > 1000хватает одной истинной стороны, а карта есть, поэтому результатtrue. !$hasCardпереворачивает значение:trueстановитсяfalse.
Сравнения выполняются раньше && и ||, поэтому скобки вокруг $sum > 1000 не нужны.
Три оператора
&& — «и»
$a && $b истинно, только когда истинны обе стороны. Если хотя бы одна ложна, ложно и всё выражение.
|| — «или»
$a || $b истинно, когда истинна хотя бы одна сторона. Ложно оно, только когда ложны обе.
! — «не»
!$a даёт true для ложного значения и false для истинного. Если значение не bool, PHP сначала приводит его, как это делает (bool): !0 даёт true. ! выполняется раньше сравнения: !$sum > 1000 значит (!$sum) > 1000, поэтому пишите !($sum > 1000).
Результат логического оператора — всегда bool: 1 && 'a' даёт bool(true). Есть ещё xor, «исключающее или»: оно истинно, когда истинна ровно одна сторона.
Вычисление по короткой схеме
Кассир не станет пересчитывать чек, если карты нет: правило «карта и чек больше 1000» уже не выполнится. PHP поступает так же, и это называют вычислением по короткой схеме:
- если левая сторона
&&ложна, правую PHP не вычисляет; - если левая сторона
||истинна, правую он тоже не вычисляет.
Чтобы это увидеть, возьмём функцию, которая печатает слово при каждом вызове:
function check()
{
echo 'called ';
return true;
}
var_dump(false && check()); // bool(false)
var_dump(true && check()); // called bool(true)Разберём по шагам:
- В
false && check()левая сторона ложна, функция не вызывается, иcalledне печатается. - В
true && check()ответ зависит от правой стороны, поэтому PHP вызываетcheck(). Она печатаетcalled, а потомvar_dumpпечатаетbool(true).
Здесь картинка с кассиром неточна. Живой кассир может всё же взглянуть на чек, а PHP правую сторону не трогает совсем. Функция в ней не вызывается, и её echo не срабатывает.
and и or слабее =
В PHP есть и операторы-слова and и or. Считают они то же, что && и ||, но выполняются в другой момент. Порядок действий касается и присваивания: && и || выполняются раньше =, а and и or — позже.
$x = true && false;
var_dump($x); // bool(false)
$y = true and false;
var_dump($y); // bool(true)Разберём по строкам:
- В первой строке
&&выполняется раньше=, и$xполучает результатtrue && false, то естьfalse. - Во второй строке первым выполняется
=:$yполучаетtrue. Потом PHP вычисляетandсfalse, и этот результат никуда не записывается.
Разницу между && и and часто спрашивают на собеседовании. Ответ:
- значение они вычисляют одинаково;
&&связывает сильнее=, аand— слабее;- поэтому в присваивании
andдаёт не тот результат, которого ждут.
С || и or всё так же. В условиях и присваиваниях пишите &&, || и !.
Частая ошибка
Право войти записывают в переменную через and:
$age = 20;
$hasTicket = false;
$canEnter = $age >= 18 and $hasTicket; // ✗
var_dump($canEnter); // bool(true)Билета нет, а в $canEnter лежит true. Присваивание выполнилось первым и записало результат $age >= 18, а проверка билета ушла в никуда. PHP не сообщает об ошибке. С && всё выражение вычисляется до записи: $age >= 18 && $hasTicket даёт false.
Главное
&&истинно, когда истинны обе стороны,||— когда хотя бы одна, а!переворачивает значение.- Если ответ ясен по левой стороне, PHP правую не вычисляет.
andиorвычисляют то же, что&&и||, но выполняются после=.- В присваиваниях пишите
&&и||:$x = true and falseоставляет в$xзначениеtrue.