PHP: Результат логических выражений
В логических выражениях можно использовать не только значения типа bool. Числа и строки тоже могут быть операндами логических операций. В этом уроке разберем, как PHP обращается с ними и каким будет результат таких выражений.
Falsy и truthy значения
Когда значение попадает в логический контекст, PHP приводит его к true или false. В PHP есть фиксированный набор значений, которые считаются ложными (falsy). К ним относятся false, число 0 (и 0.0), пустая строка '', строка '0', а также специальное значение null — «отсутствие значения».
Все остальные значения считаются истинными (truthy). Это, например, любое ненулевое число (1, -3.5) и непустая строка ('hi', 'hello').
Убедиться в этом можно с помощью двойного отрицания !!, которое приводит любое значение к типу bool: первое отрицание превращает значение в логическое (и инвертирует его), а второе возвращает обратно:
<?php
var_dump(!!'hello'); // => bool(true) — непустая строка — truthy
var_dump(!!''); // => bool(false) — пустая строка — falsy
var_dump(!!0); // => bool(false) — ноль — falsy
var_dump(!!-3.5); // => bool(true) — ненулевое число — truthy
var_dump(!!'0'); // => bool(false) — строка '0' — falsy, особенность PHPЭтим приемом пользуются, чтобы явно поменять тип данных: результатом двойного отрицания всегда будет значение типа bool.
Как работают логические выражения
В некоторых языках операторы «И» и «ИЛИ» возвращают один из своих операндов, поэтому результатом может быть строка или число. PHP устроен иначе: логические операторы && и || всегда возвращают значение типа bool — true или false:
<?php
var_dump('hello' && 'world'); // => bool(true) — оба операнда truthy
var_dump('' && 'world'); // => bool(false) — первый операнд falsy
var_dump(0 || 1); // => bool(true) — второй операнд truthy
var_dump('' || 0); // => bool(false) — оба операнда falsyПорядок вычисления зависит от приоритета операторов:
Приоритет (от высокого к низкому):
() скобки
↓
! отрицание
↓
&& логическое И
↓
|| логическое ИЛИНестрогое сравнение
Преобразование типов происходит и при нестрогом сравнении. Вспомните операторы == и != из урока про логический тип: они сравнивают значения, предварительно преобразовав типы. Поэтому, с точки зрения ==, пустая строка и false равны:
<?php
var_dump('' === false); // => bool(false)
var_dump('' == false); // => bool(true)Пустая строка и false — это разные значения, поэтому строгий оператор === говорит «Ложь! Они не равны!». Но оператор == преобразует операнды и считает их равными. Это преобразование неявное, поэтому по возможности избегайте операторов == и !=.
Ошибка выбора
Представим задачу, в которой нужно проверить, что значение равно либо одному, либо другому. Например, переменная $value должна содержать одно из двух значений: 'first' или 'second'. Начинающие разработчики иногда записывают это выражение так:
<?php
$value === ('first' || 'second');В голове мы это себе примерно так и представляем, но языки работают по-другому, поэтому такой код приведет к неверному результату. Как его правильно прочитать? Первым делом вычисляется все, что указано в скобках, то есть 'first' || 'second'. Обе строки непустые, то есть truthy, поэтому результатом будет true. Теперь можно заменить исходное выражение на частично вычисленное:
<?php
$value === true;Совсем не то, что мы ожидали: строка 'first' не равна true при строгом сравнении, поэтому выражение всегда ложно. А теперь вернемся к началу и напишем проверку правильно:
<?php
// Скобки ставить не обязательно,
// потому что приоритет === выше, чем приоритет ||
$value === 'first' || $value === 'second';Задание
Напишите функцию isFalsy(), которая проверяет, трактуется ли переданное значение как ложное (falsy) с точки зрения PHP. Для выполнения этой проверки сравните переданное значение с false, используя нестрогое сравнение ==.
<?php
isFalsy(false); // true
isFalsy(0); // true
isFalsy('help'); // false
isFalsy(10); // falseПолезное
PHP: Результат логических выражений
В логических выражениях можно использовать не только значения типа bool. Числа и строки тоже могут быть операндами логических операций. В этом уроке разберем, как PHP обращается с ними и каким будет результат таких выражений.
Falsy и truthy значения
Когда значение попадает в логический контекст, PHP приводит его к true или false. В PHP есть фиксированный набор значений, которые считаются ложными (falsy). К ним относятся false, число 0 (и 0.0), пустая строка '', строка '0', а также специальное значение null — «отсутствие значения».
Все остальные значения считаются истинными (truthy). Это, например, любое ненулевое число (1, -3.5) и непустая строка ('hi', 'hello').
Убедиться в этом можно с помощью двойного отрицания !!, которое приводит любое значение к типу bool: первое отрицание превращает значение в логическое (и инвертирует его), а второе возвращает обратно:
<?php
var_dump(!!'hello'); // => bool(true) — непустая строка — truthy
var_dump(!!''); // => bool(false) — пустая строка — falsy
var_dump(!!0); // => bool(false) — ноль — falsy
var_dump(!!-3.5); // => bool(true) — ненулевое число — truthy
var_dump(!!'0'); // => bool(false) — строка '0' — falsy, особенность PHPЭтим приемом пользуются, чтобы явно поменять тип данных: результатом двойного отрицания всегда будет значение типа bool.
Как работают логические выражения
В некоторых языках операторы «И» и «ИЛИ» возвращают один из своих операндов, поэтому результатом может быть строка или число. PHP устроен иначе: логические операторы && и || всегда возвращают значение типа bool — true или false:
<?php
var_dump('hello' && 'world'); // => bool(true) — оба операнда truthy
var_dump('' && 'world'); // => bool(false) — первый операнд falsy
var_dump(0 || 1); // => bool(true) — второй операнд truthy
var_dump('' || 0); // => bool(false) — оба операнда falsyПорядок вычисления зависит от приоритета операторов:
Приоритет (от высокого к низкому):
() скобки
↓
! отрицание
↓
&& логическое И
↓
|| логическое ИЛИНестрогое сравнение
Преобразование типов происходит и при нестрогом сравнении. Вспомните операторы == и != из урока про логический тип: они сравнивают значения, предварительно преобразовав типы. Поэтому, с точки зрения ==, пустая строка и false равны:
<?php
var_dump('' === false); // => bool(false)
var_dump('' == false); // => bool(true)Пустая строка и false — это разные значения, поэтому строгий оператор === говорит «Ложь! Они не равны!». Но оператор == преобразует операнды и считает их равными. Это преобразование неявное, поэтому по возможности избегайте операторов == и !=.
Ошибка выбора
Представим задачу, в которой нужно проверить, что значение равно либо одному, либо другому. Например, переменная $value должна содержать одно из двух значений: 'first' или 'second'. Начинающие разработчики иногда записывают это выражение так:
<?php
$value === ('first' || 'second');В голове мы это себе примерно так и представляем, но языки работают по-другому, поэтому такой код приведет к неверному результату. Как его правильно прочитать? Первым делом вычисляется все, что указано в скобках, то есть 'first' || 'second'. Обе строки непустые, то есть truthy, поэтому результатом будет true. Теперь можно заменить исходное выражение на частично вычисленное:
<?php
$value === true;Совсем не то, что мы ожидали: строка 'first' не равна true при строгом сравнении, поэтому выражение всегда ложно. А теперь вернемся к началу и напишем проверку правильно:
<?php
// Скобки ставить не обязательно,
// потому что приоритет === выше, чем приоритет ||
$value === 'first' || $value === 'second';Задание
Напишите функцию isFalsy(), которая проверяет, трактуется ли переданное значение как ложное (falsy) с точки зрения PHP. Для выполнения этой проверки сравните переданное значение с false, используя нестрогое сравнение ==.
<?php
isFalsy(false); // true
isFalsy(0); // true
isFalsy('help'); // false
isFalsy(10); // falseПолезное
Ваше упражнение проверяется по этим тестам
<?php
namespace HexletBasics\Logic\LogicalExpressions;
use HexletBasics\Exercise\TestCase;
class SolutionTest extends TestCase
{
public function test()
{
$this->assertTrue(isFalsy(''));
$this->assertFalse(isFalsy(' '));
$this->assertTrue(isFalsy(null));
$this->assertTrue(isFalsy(false));
$this->assertTrue(isFalsy('0'));
$this->assertFalse(isFalsy(true));
$this->assertFalse(isFalsy(3));
$this->assertFalse(isFalsy('help'));
}
}Решение учителя откроется через:
20:00
