Объявления типов добавляют параметрам функций, значениям возврата, начиная с PHP 7.4.0 свойствам класса и начиная с PHP 8.3.0 константам класса. Объявления типов гарантируют, что при вызове значение принадлежит заданному типу, иначе PHP выбросит ошибку TypeError.
Каждый тип, который поддерживает PHP, за исключением ресурсов (resource), разрешается указывать в пользовательском объявлении типа. Страница содержит журнал изменений доступности отдельных типов и документацию, которая описывает правила объявления типов.
Замечание:
Класс, который реализует метод интерфейса или переопределяет метод родительского класса, подчиняется правилам совместимости. Метод совместим, если следует правилам вариантности.
Версия | Описание |
---|---|
8.3.0 | Добавили поддержку типизации констант классов, интерфейсов, трейтов и перечислений. |
8.2.0 | Добавили поддержку DNF-типов. |
8.2.0 | Добавили поддержку самостоятельного типа true. |
8.2.0 | Типы null и false разрешили указывать отдельно. |
8.1.0 | Добавили поддержку пересечений типов. |
8.1.0 | Возврат по ссылке из функции с типом значения возврата void устарел. |
8.1.0 | Для значения возврата добавили поддержку типа never. |
8.0.0 | Для значения возврата добавили поддержку типа mixed. |
8.0.0 | Для значения возврата добавили поддержку типа static. |
8.0.0 | Добавили поддержку объединения типов. |
7.4.0 | Добавили поддержку типизации свойств классов. |
7.2.0 | Для значения возврата добавили поддержку типа object. |
7.1.0 | Для значения возврата добавили поддержку типа iterable. |
7.1.0 | Для значения возврата добавили поддержку типа void. |
7.1.0 | Для значения возврата добавили поддержку обнуляемого типа. |
Атомарные типы ведут себя прямолинейно, но с рядом оговорок, которые описывает этот раздел.
Псевдонимы имён для скалярных типов, к которым относятся типы bool, int,
float и string, не поддерживаются.
Вместо назначения псевдонимов названия классов и интерфейсов трактуются как типы.
Например, буквальное название boolean
в объявлении типа потребует,
чтобы значение выполняло условие instanceof
в отношении класса или интерфейса
boolean
, а не принадлежало типу bool:
<?php
function test(boolean $param) {}
test(true);
?>
Результат выполнения приведённого примера в PHP 8:
Warning: "boolean" will be interpreted as a class name. Did you mean "bool"? Write "\boolean" to suppress this warning in /in/9YrUX on line 2 Fatal error: Uncaught TypeError: test(): Argument #1 ($param) must be of type boolean, bool given, called in - on line 3 and defined in -:2 Stack trace: #0 -(3): test(true) #1 {main} thrown in - on line 2
Замечание:
Возврат по ссылке из void-функции устарел начиная с PHP 8.1.0, поскольку такая функция противоречива. Раньше при вызове такой функции уже выдавалась ошибка уровня
E_NOTICE
: Только ссылки на переменные должны возвращаться по ссылке.<?php
function &test(): void {}
?>
Свойствам класса нельзя объявлять тип callable.
Замечание: Тип callable нельзя указывать как название функции.
Параметр, который принимает ссылку, проверяет тип переменной только при входе в функцию, в начале вызова, но не при возврате из функции, поэтому в функции возможно изменение типа ссылки на переменную.
Пример #1 Типизированный параметр, который принимает ссылку
<?php
function array_baz(array &$param)
{
$param = 1;
}
$var = [];
array_baz($var);
var_dump($var);
array_baz($var);
?>
Вывод приведённого примера будет похож на:
int(1) Fatal error: Uncaught TypeError: array_baz(): Argument #1 ($param) must be of type array, int given, called in - on line 9 and defined in -:2 Stack trace: #0 -(9): array_baz(1) #1 {main} thrown in - on line 2
На объявления составных типов распространяется ряд ограничений; компилятор выполняет проверку избыточности типов, чтобы предотвратить простые ошибки.
Комбинирование пересечений и объединений типов оставалось невозможным до PHP 8.2.0 и введения DNF-типов.
Невозможно определить в объединённом типе два одноэлементных типа false и true. Вместо этого указывают тип bool.
До PHP 8.2.0 запрещали определять типы false и null отдельно,
поэтому объединение типов, которое состояло только из этих типов, оставалось недопустимым.
К таким объединениям относятся типы: false, false|null
и ?false
.
Объявление отдельного базового типа помечают как nullable путём
добавления к типу префикса в виде
вопросительного знака (?
).
Поэтому типы ?T
и T|null
идентичны.
Замечание: Этот синтаксис поддерживается с PHP 7.1.0 и предшествует поддержке объединения типов.
Замечание:
Ещё один способ объявить nullable-параметр — указать значением по умолчанию значение
null
. Объявлять тип таким способом не рекомендуют, поскольку изменение значения по умолчанию в дочернем классе нарушит совместимость типов, и к объявлению типа потребуется добавить тип null. Это поведение также устарело начиня с PHP 8.4.Пример #2 Старый способ указать nullable-параметр
<?php
class C {}
function f(C $c = null)
{
var_dump($c);
}
f(new C());
f(null);
?>Результат выполнения приведённого примера:
object(C)#1 (0) { } NULL
Правила объявления составных типов предусматривают ряд ограничений. При компиляции кода с избыточными типами, которые возможно обнаружить без загрузки классов, возникнет ошибка. Примеры ошибок в объявлениях составных типов включают:
int|string|INT
или Countable&Traversable&COUNTABLE
,
поскольку после разрешения названия типа внутренними средствами языка тип встречается больше одного раза.
Замечание: Эти проверки не гарантируют, что тип «минимален» и не содержит повторений или избыточных типов, поскольку для этого потребовалось бы загрузить все указанные типы классов.
Например, если типы A
и B
— псевдонимы классов,
то составной тип A|B
остаётся корректным объединением типов,
даже если тип получится свести либо к A
, либо к B
.
Аналогично, если класс B extends A {}
, то составной тип A|B
также относится
к корректному объединению типов, даже если тип получится свести только к типу A
.
<?php
function foo(): int|INT {} // Запрещено
function foo(): bool|false {} // Запрещено
function foo(): int&Traversable {} // Запрещено
function foo(): self&Traversable {} // Запрещено
use A as B;
function foo(): A|B {} // Запрещено (оператор "use" только создаёт псевдоним через механизм разрешения имён, а не отдельный тип)
function foo(): A&B {} // Запрещено (оператор "use" только создаёт псевдоним через механизм разрешения имён, а не отдельный тип)
class_alias('X', 'Y');
function foo(): X|Y {} // Разрешено (избыточность обнаружится только при выполнении кода)
function foo(): X&Y {} // Разрешено (избыточность обнаружится только при выполнении кода)
?>
Пример #3 Пример объявления типа через название класса
<?php
class C {}
class D extends C {}
// Класс не наследует класс C
class E {}
function f(C $c)
{
echo get_class($c)."\n";
}
f(new C);
f(new D);
f(new E);
?>
Результат выполнения приведённого примера в PHP 8:
C D Fatal error: Uncaught TypeError: f(): Argument #1 ($c) must be of type C, E given, called in /in/gLonb on line 14 and defined in /in/gLonb:8 Stack trace: #0 -(14): f(Object(E)) #1 {main} thrown in - on line 8
Пример #4 Пример объявления типа через название интерфейса
<?php
interface I
{
public function f();
}
class C implements I
{
public function f() {}
}
// Класс не реализует интерфейс I
class E {}
function f(I $i)
{
echo get_class($i) . "\n";
}
f(new C);
f(new E);
?>
Результат выполнения приведённого примера в PHP 8:
C Fatal error: Uncaught TypeError: f(): Argument #1 ($i) must be of type I, E given, called in - on line 13 and defined in -:8 Stack trace: #0 -(13): f(Object(E)) #1 {main} thrown in - on line 8
Пример #5 Пример объявления типа значения возврата
<?php
function sum($a, $b): float
{
return $a + $b;
}
// Обратите внимание, что функция вернёт значение с типом float
var_dump(sum(1, 2));
?>
Результат выполнения приведённого примера:
float(3)
Пример #6 Возврат объекта
<?php
class C {}
function getC(): C
{
return new C();
}
var_dump(getC());
?>
Результат выполнения приведённого примера:
object(C)#1 (0) { }
Пример #7 Объявление параметра с обнуляемым типом
<?php
class C {}
function f(?C $c)
{
var_dump($c);
}
f(new C());
f(null);
?>
Результат выполнения приведённого примера:
object(C)#1 (0) { } NULL
Пример #8 Объявление типа значения возврата как обнуляемого
<?php
function get_item(): ?string
{
if (isset($_GET['item'])) {
return $_GET['item'];
} else {
return null;
}
}
?>
Пример #9 Объявление типа свойства класса
<?php
class User
{
public static string $foo = 'foo';
public int $id;
public string $username;
public function __construct(int $id, string $username)
{
$this->id = $id;
$this->username = $username;
}
}
?>
В нестрогом режиме, в котором проверка типов работает по умолчанию, PHP преобразовывает значения неправильного типа в скалярный тип, который указали в объявлении, поэтому, например, при передаче в параметр с типом string аргумента с типом int функция получит значение с типом string.
Строгий режим включается отдельно для каждого файла. В строгом режиме механизм проверки типов признаёт только значения, которые соответствуют типу объявления, иначе выбрасывается ошибка TypeError. Единственное исключение из правила — значения с типом int, которые передают в объявления типа float.
Объявление директивы strict_types
не влияет на вызовы функций внутри встроенных функций.
Строгий режим включают инструкцией declare
с объявлением
директивы strict_types
:
Замечание:
На строгость проверки типов при вызове функций влияет режим, который объявили внутри файла вызова, а не режим, который установили в файле объявления функции. Механизм проверки типов применит режим, который установили на стороне вызова, и автоматически приведёт типы значений, если файл без строгой типизации вызывает функцию, которую объявили в файле со строгой типизацией.
Замечание:
Строгая типизация определяется только для объявлений скалярных типов.
Пример #10 Строгая типизация для значений аргументов
<?php
declare(strict_types=1);
function sum(int $a, int $b)
{
return $a + $b;
}
var_dump(sum(1, 2));
var_dump(sum(1.5, 2.5));
?>
Результат выполнения приведённого примера в PHP 8:
int(3) Fatal error: Uncaught TypeError: sum(): Argument #1 ($a) must be of type int, float given, called in - on line 9 and defined in -:4 Stack trace: #0 -(9): sum(1.5, 2.5) #1 {main} thrown in - on line 4
Пример #11 Приведение типов для значений аргументов
<?php
function sum(int $a, int $b)
{
return $a + $b;
}
var_dump(sum(1, 2));
// Механизм проверки типов приведёт значения аргументов к целым числам: обратите внимание на вывод!
var_dump(sum(1.5, 2.5));
?>
Результат выполнения приведённого примера:
int(3) int(3)
Пример #12 Строгая типизация для значений возврата
<?php
declare(strict_types=1);
function sum($a, $b): int
{
return $a + $b;
}
var_dump(sum(1, 2));
var_dump(sum(1, 2.5));
?>
Результат выполнения приведённого примера:
int(3) Fatal error: Uncaught TypeError: sum(): Return value must be of type int, float returned in -:5 Stack trace: #0 -(9): sum(1, 2.5) #1 {main} thrown in - on line 5