Скалярные типы
В прошлом уроке в банки клали числа и строки. Теперь посмотрим, чем одни значения отличаются от других.
Представьте, что на каждой банке есть наклейка с видом содержимого: «целое число», «дробное число», «текст». Заранее её не клеят: PHP сам меняет наклейку, когда вы кладёте в банку новое значение. Этот вид значения называют типом. Тип есть у значения, а не у переменной, поэтому в одной переменной сейчас может лежать число, а строкой ниже — текст:
<?php
$x = 12 / 4;
var_dump($x); // int(3)
$x = 9 / 2;
var_dump($x); // float(4.5)
$x = 'nine';
var_dump($x); // string(4) "nine"Давайте разберём по строкам:
12 / 4делится нацело, и в$xпопадает целое число3.var_dump($x)печатает тип и значение:int(3).9 / 2нацело не делится, и в$xпопадает дробное4.5— наклейка сменилась наfloat.$x = 'nine'кладёт в ту же переменную строку, иvar_dumpпечатаетstring(4) "nine".
Когда оба числа целые, оператор / возвращает целое число, если деление получается нацело, и дробное — если остаётся дробная часть. Поэтому одна и та же операция дала два разных типа.
Наклейка здесь — упрощение. PHP хранит тип вместе с самим значением, а не на банке. Поэтому при $b = $a тип переезжает в $b вместе с копией значения.
Четыре скалярных типа и null
Скалярный тип — это вид простого значения: число, строка или ответ «да» или «нет». Таких типов в PHP четыре, и к ним добавляется особый тип null.
int
Целые числа без дробной части: 42, -7, 0. Ими записывают количество штук, номера заказов и возраст.
float
Дробные числа: 3.5, -0.25. Такое число называют числом с плавающей точкой. Дробную часть в коде отделяет точка, а не запятая. Число 2.0 — тоже float, хотя дробная часть у него нулевая.
string
Текст в кавычках: 'Anna', '42'. Строка '42' — это текст из двух символов, а не число.
bool
Логическое значение: true или false, «да» или «нет». Оно отвечает на вопросы вроде «оплачен ли заказ».
null
Единственное значение null означает «в банке ничего нет». Переменная со значением null при этом существует: в отличие от переменной, которой ничего не присваивали, её читают без предупреждения.
Как читать var_dump
Функция var_dump печатает тип и значение, каждое значение — на отдельной строке:
var_dump(42); // int(42)
var_dump(2.0); // float(2)
var_dump('abcd'); // string(4) "abcd"
var_dump(false); // bool(false)
var_dump(null); // NULLЧто означает каждая строка вывода:
int(42)— целое число42;float(2)— дробное число:var_dumpне печатает нулевую дробную часть, но тип называет;string(4) "abcd"— строка: в скобках её длина, в кавычках сама строка;bool(false)— логическое значение;NULL— значениеnull, без скобок.
В var_dump можно передать несколько значений через запятую. Каждое из них он напечатает на своей строке, в том же формате.
Есть и функция gettype, которая возвращает название типа строкой. Но названия у неё старые: gettype(3.5) даёт 'double', а gettype(42) — 'integer'. Поэтому тип в курсе показываем через var_dump.
Дробные числа неточны
Число с плавающей точкой хранится в двоичном виде, и 0.1 в нём записать точно нельзя. Так же и в десятичной записи нельзя точно записать одну треть: 0.333… где-то приходится обрезать.
var_dump(0.1 + 0.2); // float(0.30000000000000004)
echo 0.1 + 0.2, "\n"; // 0.3var_dump показывает число полностью, и видно, что сумма чуть больше 0.3. echo печатает дробное число с точностью до 14 значащих цифр и округляет его до 0.3, поэтому ошибку не видно.
Это классический вопрос на собеседовании: «Почему 0.1 + 0.2 не равно 0.3?» Ответ: float хранит двоичное приближение, а не точное десятичное число. Поэтому деньги считают в копейках и хранят как int.
Частая ошибка
Дробную часть отделили запятой, как принято в русском тексте:
$price = 3,5; // ✗Parse error: syntax error, unexpected token ","Это ошибка разбора: PHP не понимает, что делает запятая после 3, и не запускает файл вовсе. В коде дробную часть всегда отделяет точка: $price = 3.5;.
Главное
- Тип есть у значения, а не у переменной: новое значение приносит свой тип.
- Скалярных типов четыре:
int,float,string,bool. Есть ещё особый типnull. var_dumpпечатает тип и значение:int(3),float(4.5),string(4) "abcd",bool(true),NULL./с двумяintдаётint, когда они делятся нацело, иначеfloat;0.1 + 0.2— не ровно0.3.