Перейти к содержимому
Теория · Операторы и сравнение · урок 6 из 8

Логические операторы

Одно сравнение отвечает на один вопрос. Но часто ответ зависит сразу от двух: есть ли у покупателя карта и набрал ли он покупок больше чем на тысячу.

Вернёмся к кассе. Скидку кассир даёт по правилу «карта есть И чек больше 1000». По другому правилу подарок положен, если «карта есть ИЛИ сегодня праздник». Связки «и», «или», «не» в PHP записывают логическими операторами.

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)

Разберём по строкам:

  1. В $hasCard && $sum > 1000 сравнение 800 > 1000 даёт false, и всё выражение ложно: для && обе стороны должны быть истинны.
  2. В $hasCard || $sum > 1000 хватает одной истинной стороны, а карта есть, поэтому результат true.
  3. !$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 не вычисляет;
  • если левая сторона || истинна, правую он тоже не вычисляет.

Чтобы это увидеть, возьмём функцию, которая печатает слово при каждом вызове:

PHP
function check()
{
    echo 'called ';
    return true;
}

var_dump(false && check()); // bool(false)
var_dump(true && check()); // called bool(true)

Разберём по шагам:

  1. В false && check() левая сторона ложна, функция не вызывается, и called не печатается.
  2. В true && check() ответ зависит от правой стороны, поэтому PHP вызывает check(). Она печатает called, а потом var_dump печатает bool(true).

Здесь картинка с кассиром неточна. Живой кассир может всё же взглянуть на чек, а PHP правую сторону не трогает совсем. Функция в ней не вызывается, и её echo не срабатывает.

and и or слабее =

В PHP есть и операторы-слова and и or. Считают они то же, что && и ||, но выполняются в другой момент. Порядок действий касается и присваивания: && и || выполняются раньше =, а and и or — позже.

PHP
$x = true && false;
var_dump($x); // bool(false)
$y = true and false;
var_dump($y); // bool(true)

Разберём по строкам:

  1. В первой строке && выполняется раньше =, и $x получает результат true && false, то есть false.
  2. Во второй строке первым выполняется =: $y получает true. Потом PHP вычисляет and с false, и этот результат никуда не записывается.

Разницу между && и and часто спрашивают на собеседовании. Ответ:

  • значение они вычисляют одинаково;
  • && связывает сильнее =, а and — слабее;
  • поэтому в присваивании and даёт не тот результат, которого ждут.

С || и or всё так же. В условиях и присваиваниях пишите &&, || и !.

Частая ошибка

Право войти записывают в переменную через and:

PHP
$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.