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

Арифметика

Чему вы научитесь

Чему вы научитесь:

  • считать через +, -, *, /, % и ** и предсказывать тип результата;
  • менять переменную через ++, += и .= и отличать $i++ от ++$i;
  • сравнивать значения через == и === и объяснять правило PHP 8 для чисел и строк;
  • подставлять значение по умолчанию через ?? и ?: и помнить, что and слабее =.
17 пирожков по коробкам по пять — три полные коробки intdiv, два лишних % 5 = 2 и калькулятор с 3.4

Представьте калькулятор с правилами заведения. Он складывает, вычитает и умножает как в школе, но у некоторых кнопок есть свои оговорки. Кнопка / всегда оставляет дробную часть, а отбрасывает дробь отдельная кнопка intdiv.

Кнопки-знаки вроде + и / в программе называют операторами. Чаще всего оператор стоит между двумя значениями и говорит PHP, что с ними сделать. А intdiv — функция: её вызывают по имени, а числа передают в скобках. В теме о типах вы уже видели оператор / и знаете, что результат деления бывает не целым.

Возьмём задачу из жизни: 17 пирожков раскладывают по коробкам, и в каждую помещается 5. Сколько коробок заполнится целиком и сколько пирожков останется?

PHP
<?php

$pies = 17;
echo $pies / 5, "\n"; // 3.4
echo intdiv($pies, 5), "\n"; // 3
echo $pies % 5, "\n"; // 2

Давайте разберём программу по строкам:

  1. $pies / 5 печатает 3.4: обычное деление сохраняет дробную часть.
  2. intdiv($pies, 5) делит нацело и возвращает 3, и echo печатает его: столько коробок заполнится целиком.
  3. $pies % 5 печатает 2: эти два пирожка не поместились ни в одну полную коробку.

Четыре действия и степень

Арифметические операторы PHP:

  • + складывает;
  • - вычитает;
  • * умножает;
  • / делит и сохраняет дробную часть;
  • % даёт остаток от деления;
  • ** возводит в степень: 2 ** 10 — это 1024.

Тип результата зависит от значений. Сумма двух int — снова int, а если одно из чисел float, результат тоже float: 2 + 1.0 даёт float(3).

Деление ведёт себя по-своему. 10 / 5 даёт int(2), потому что делится нацело, а 7 / 2 даёт float(3.5). Во многих языках деление целых отбрасывает дробь, а в PHP для этого есть отдельная функция.

Деление нацело и остаток

Функция intdiv

intdiv($a, $b) делит одно целое число на другое и отбрасывает дробную часть. Она не округляет:

  • intdiv(17, 5) даёт 3, и 3.4 превращается в 3;
  • intdiv(19, 5) тоже даёт 3, хотя 3.8 ближе к четырём;
  • у отрицательных чисел дробь тоже отрезается: intdiv(-7, 2) даёт -3.

Оператор %

Оператор % даёт остаток — то, что не поместилось в полные коробки. Остаток 0 значит, что число разделилось нацело: 10 % 2 даёт 0, и так проверяют, что число чётное.

Остаток бывает отрицательным: его знак совпадает со знаком делимого, то есть левого числа. Поэтому -7 % 3 даёт -1, а 7 % -3 даёт 1. Здесь картинка с коробками перестаёт работать: минус семь пирожков по коробкам не разложишь, а % с отрицательными числами считает и берёт знак у делимого.

Порядок действий

Когда в выражении несколько операторов, PHP выполняет их по приоритету — заранее заданному порядку, как в школьной математике:

  1. сначала **;
  2. затем *, / и %;
  3. потом + и -;
  4. последним оператор ., который склеивает две строки в одну.

Скобки меняют этот порядок. Давайте посмотрим, что получится:

PHP
echo 2 + 3 * 4, "\n"; // 14
echo (2 + 3) * 4, "\n"; // 20
echo 'Total: ' . 2 + 3, "\n"; // Total: 5
echo 'a' . 1 + 2, "\n"; // a3

В третьей строке PHP сначала складывает 2 + 3, а потом приклеивает 5 к строке. В четвёртой то же самое: 1 + 2 даёт 3, и выходит a3. Такой порядок действует с PHP 8, а скобки 'Total: ' . (2 + 3) делают его видным с первого взгляда.

Последний пример любят давать на собеседованиях: он проверяет, знаете ли вы, что в PHP 8 сложение выполняется раньше склейки.

Здесь калькулятор перестаёт быть точной картинкой. В настоящий калькулятор строку не введёшь, а PHP склеивает строки и в '5' + 3 сам превращает '5' в число 5.

Деление на ноль

Делить на ноль нельзя, и PHP не пытается угадать ответ:

PHP
$boxes = 0;
echo $pies / $boxes, "\n"; // ✗
echo 'done', "\n";
TEXT
Fatal error: Uncaught DivisionByZeroError: Division by zero

PHP останавливает программу на этой строке: всё, что напечатано раньше, остаётся на экране, а слово done не появится. Так же останавливают программу intdiv($pies, 0) и $pies % 0.

Иногда вместо остановки нужна бесконечность. Для этого есть функция fdiv: fdiv(1, 0) возвращает INF, особое значение типа float.

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

Среднее двух чисел считают без скобок:

PHP
$a = 4;
$b = 6;
$average = $a + $b / 2; // ✗
echo $average, "\n"; // 7

Деление выполняется раньше сложения, поэтому PHP считает 4 + 3 и печатает 7 вместо 5. Сообщения об ошибке нет, и неверное число уходит дальше в программу. Возьмите сумму в скобки: ($a + $b) / 2 даёт 5.

Главное

  • / сохраняет дробную часть, а intdiv отбрасывает её; 10 / 5 даёт int, а 7 / 2 — float.
  • % даёт остаток, и его знак совпадает со знаком делимого: -7 % 3 — это -1.
  • Сначала **, затем *, / и %, потом + и -, последней склейка .; скобки меняют порядок.
  • Деление на ноль останавливает программу с DivisionByZeroError, а fdiv(1, 0) возвращает INF.