В этом уроке мы поближе познакомимся с типами данных и обсудим нюансы работы с ними.
Когда мы пишем на PHP, то не особо задумываемся над типами данных. Мы просто пишем код и ожидаем, что данные будут соответствовать нашим ожиданиям:
<?php
function sayHelloTo($name)
{
print_r("Hello, {$name}");
}
Функция выше ожидает на вход строку. Это видно по тому, как используется переменная $name
. А что, если мы ошибемся и передадим массив? Давайте попробуем:
<?php
// В функцию передается не то, что ожидается:
sayHelloTo([]);
// PHP Notice: Array to string conversion
Код отработает, но результат не будет соответствовать нашим ожиданиям. Ничего страшного в таком поведении нет — это просто цена за использование динамической типизации.
В тех местах, где входной тип особенно важен, можно добавить соответствующую проверку и генерировать исключение, если переданы неверные данные. По крайней мере так делали раньше, до введения в язык механизма type hinting.
Type Hinting — это механизм, который позволяет явно указывать типы параметров. Интерпретатор использует их и применяет исключение в тех ситуациях, когда тип не соответствует ожидаемому. Так работает в большинстве языков, где присутствует этот механизм.
В PHP используется слабая типизация, поэтому здесь все чуть сложнее. Можно жестко указать тип int
, но это не значит, что интерпретатор начнет ругаться на все остальное. Он выполнит автоматическое приведение и спокойно обработает и логический, и строковый тип данных.
Чтобы объявить тип аргумента, необходимо перед его именем добавить имя требуемого типа:
<?php
// Тип int говорит, что ожидается число
function sayHelloTo(int $name)
{
print_r("Hello, {$name}");
}
// Все, что может быть приведено к указанному типу, будет считаться подходящим
sayHelloTo(false); // Hello, 0
sayHelloTo('1'); // Hello, 1
Попробуем в качестве типа аргумента передать строку string
:
<?php
function sayHelloTo(string $name)
{
print_r("Hello, {$name}");
}
sayHelloTo([]);
// PHP Fatal error: Uncaught TypeError: Argument 1 passed to sayHelloTo() must be of the type string, array given
Теперь ошибка совсем другая — нам явно говорят, что типы не сошлись. Увидеть и исправить подобную ошибку уже значительно легче. Рассмотрим еще один пример с несколькими параметрами:
<?php
function get(string $text, int $index, $default = null)
{
$length = strlen($text);
return ($index >= 0) && ($index < $length) ? $text[$index] : $default;
}
get('hi', 3, 8); // 8
get('ho', 'hey');
// PHP Fatal error: Uncaught TypeError: Argument 2 passed to get() must be of the type integer, string given
Обратите внимание на отсутствие типа у $default
. Значение по умолчанию может быть абсолютно любым, поэтому тип не указывается.
Null
не похож на другие типы данных и ведет себя особым образом. Дело в том, что типы данных в PHP не являются nullable — то есть они не допускают значение Null
.
Представим, что мы ждем на вход значение определенного типа — например, строку. В PHP строка не может иметь значение Null
. Но это ограничение можно обойти. Можно указать значение, по умолчанию равное Null
, и тогда указанный тип становится nullable — появится возможность передавать Null
снаружи.
Посмотрим, как это выглядит в коде:
Не nullable:
<?php
function printStr(string $value)
{
echo $value;
}
printStr(null);
// PHP Fatal error: Uncaught TypeError: Argument 1 passed to printStr() must be of the type string, null given
Nullable:
<?php
function printStr(string $value = null)
{
echo $value;
}
printStr(null);
Начиная с версии PHP 7.2, в языке появилась возможность указывать тип не только для входящих параметров, но и для возврата функции. Оно записывается через двоеточие после закрывающей скобки:
<?php
function sum(int $a, int $b): int
{
return $a + $b;
}
Если мы ошибемся в теле функции выше и вернем строку, то интерпретатор скажет об этом:
TypeError: Return value of sum() must be of the type integer, string returned
Еще функция может ничего не возвращать. Например, если она принимает строку, добавляет в конец восклицательный знак и затем печатает результат на экран:
<?php
function sayItLoud(string $text): void
{
$loudText = "{$text}!";
print_r($loudText);
}
Чтобы показать, что функция ничего не возвращает, нужно написать в ее сигнатуре после двоеточия — void
.
Строгие типы
В его базовом варианте Type Hinting не очень помогает выявить ошибки типов. Он больше полезен в качестве документации и подсказок в редакторе.
Но в PHP есть специальная директива, включающая режим строгой проверки:
<?php
// Включаем режим строгой проверки
declare(strict_types = 1);
function AddIntAndFloat(int $a, float $b): int
{
return $a + $b;
}
echo AddIntAndFloat(1.4, '2');
// Fatal error: Uncaught TypeError: Argument 1 passed to AddIntAndFloat() must be of the type int, float given
echo AddIntAndFloat(1, '2');
// Fatal error: Uncaught TypeError: Argument 2 passed to AddIntAndFloat() must be of the type float, string given
В таком варианте не происходит автоматического преобразования типов. PHP выполняет точную проверку и выводит ошибку, если типы не совпали.
Типы значений, допускающие значение NULL
Если поставить знак ?
перед названием типа данных, то он помечается как обнуляемый — то есть допускающий значение Null
.
Это значит, что значение может быть как указанного типа, так и null
. Это работает как для входных параметров, так и для возвращаемых функцией значений:
<?php
function isPersonMrSmith(?string $person): bool
{
// Тут какая-то логика
}
Запись выше означает, что функция isPersonMrSmith()
может принять в качестве параметра строку или null
.
Стоит сказать, что null
должен быть передан явно — isPersonMrSmith(null)
. Иначе интерпретатор выдаст ошибку:
isPersonMrSmith();
// Fatal error: Uncaught ArgumentCountError: Too few arguments to function
Посмотрим, как ?
работает с типом возвращаемого значения:
<?php
public function getName(string $person): ?string
{
// Тут какая-то логика
}
Функция getName()
принимает переменную $person
. Затем функция должна вернуть строку с именем человека. Но иногда строки с именем нет — тогда возвращается null
.
Дополнительные материалы
- Официальная документация
- Строгая типизация
- Как включить строгую типизацию в PHP и для чего ее использовать
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты