Type declarations
Оновлено: 12.05.2023
Оголошення типів можна додавати до аргументів функцій, значень, що повертаються, і, починаючи з версії PHP 7.4.0, до властивостей класів. Вони гарантують, що значення має вказаний тип під час виклику, інакше буде згенеровано помилку TypeError.
Кожен тип, який підтримує PHP, за винятком ресурсу, може бути використаний в оголошенні типу user-land. Ця сторінка містить журнал змін доступності різних типів і документацію про їх використання в оголошеннях типів.
Зауважте:
Коли клас реалізує метод інтерфейсу або перевизначає метод, який вже був визначений батьківським класом, він повинен бути сумісним з вищезгаданим визначенням. Метод є сумісним, якщо він відповідає правилам відхилень.
Базові типи мають просту поведінку з деякими незначними застереженнями, які описано в цьому розділі.
Псевдоніми для скалярних типів (bool, int, float, string) не підтримуються. Замість цього вони розглядаються як імена класів або інтерфейсів. Наприклад, використання boolean як оголошення типу вимагатиме, щоб значення було екземпляром класу або інтерфейсу boolean, а не типу bool:
<?php
function test(boolean $param) {}
test(true);
?>
Зауважте:
Повернення за посиланням з функції void є застарілим, починаючи з версії PHP 8.1.0, оскільки така функція є суперечливою. Раніше вона вже видавала наступне E_NOTICE при виклику: Only variable references should be returned by reference.
<?php
function &test(): void {}
?>
Цей тип не можна використовувати як оголошення типу властивості класу.
Зауваження: Неможливо вказати сигнатуру функції.
Якщо параметр, що передається за посиланням, має оголошення типу, то тип змінної перевіряється лише при вході у функцію, на початку виклику, але не при поверненні функції. Це означає, що функція може змінювати тип посилання на змінну.
Приклад #1 Типізовані параметри переходу за посиланням
<?php
function array_baz(array &$param)
{
$param = 1;
}
$var = [];
array_baz($var);
var_dump($var);
array_baz($var);
?>
У наведеному вище прикладі буде виведено щось подібне до
На оголошення складених типів накладається декілька обмежень, і під час компіляції виконується перевірка на надмірність, щоб запобігти простим помилкам.
До версії PHP 8.2.0 і введення типів DNF було неможливо об'єднати типи перетину з типами об'єднання.
Неможливо об'єднати два літеральні типи false та true в одному об'єднаному типі. Замість цього використовуйте bool.
До версії PHP 8.2.0, оскільки false і null не можна було використовувати як окремі типи, об'єднаний тип, що складається лише з цих типів, був заборонений. До таких типів належать: false, false|null та ?false.
Окреме оголошення базового типу можна позначити як нульове, додавши до нього знак питання (?). Таким чином, ?T та T|null є ідентичними.
Зауваження: Цей синтаксис підтримується починаючи з версії PHP 7.1.0 і передує підтримці узагальнених типів об'єднань.
Зауважте:
Також можна отримати аргументи, які можна обнулити, зробивши null значенням за замовчуванням. Це не рекомендується, оскільки при зміні значення за замовчуванням у дочірньому класі буде порушено сумісність типів, оскільки до оголошення типу потрібно буде додати нульовий тип.
Приклад #2 Старий спосіб зробити аргументи неприпустимими
<?php
class C {}
function f(C $c = null) {
var_dump($c);
}
f(new C);
f(null);
?>
Вищенаведений приклад виведе:
Для виявлення простих помилок в оголошеннях складених типів, надлишкові типи, які можна виявити, не виконуючи завантаження класу, призведуть до помилки під час компіляції. До них відносяться
Кожен тип з перетворенням імен може зустрічатися лише один раз. Такі типи, як int|string|INT або Countable&Traversable&COUNTABLE призведуть до помилки.
Використання змішаних типів призводить до помилки.
Для об'єднаних типів:
- Якщо використовується bool, не можна додатково використовувати false або true.
- Якщо використовується об'єкт, не можна додатково використовувати типи класів.
- Якщо використовується iterable, не можна додатково використовувати array та Traversable.
Для типів перетину:
- Використання типу, який не є типом класу, призводить до помилки.
- Використання self, parent або static призводить до помилки.
Для типів DNF:
- Якщо використовується більш загальний тип, більш обмежений тип є надлишковим.
- Використання двох однакових типів перетину.
- Якщо використовується bool, не можна додатково використовувати false або true.
- Якщо використовується об'єкт, не можна додатково використовувати типи класів.
- Якщо використовується iterable, не можна додатково використовувати array та Traversable.
- Використання типу, який не є типом класу, призводить до помилки.
- Використання self, parent або static призводить до помилки.
- Якщо використовується більш загальний тип, то більш обмежувальний тип є надлишковим.
Використання двох однакових типів перетину.
Зауваження: Це не гарантує, що тип буде "мінімальним", оскільки для цього потрібно завантажити всі використовувані типи класів.
Наприклад, якщо A і B є псевдонімами класів, то A|B залишається законним типом об'єднання, навіть якщо його можна звести до A або B. Аналогічно, якщо клас B розширює A {}, то A|B також є законним типом об'єднання, навіть якщо його можна звести до просто A.
<?php
function foo(): int|INT {} // Disallowed
function foo(): bool|false {} // Disallowed
function foo(): int&Traversable {} // Disallowed
function foo(): self&Traversable {} // Disallowed
use A as B;
function foo(): A|B {} // Disallowed ("use" is part of name resolution)
function foo(): A&B {} // Disallowed ("use" is part of name resolution)
class_alias('X', 'Y');
function foo(): X|Y {} // Allowed (redundancy is only known at runtime)
function foo(): X&Y {} // Allowed (redundancy is only known at runtime)
?>
Приклад #3 Оголошення базового типу класу
<?php
class C {}
class D extends C {}
// This doesn't extend C.
class E {}
function f(C $c) {
echo get_class($c)."\n";
}
f(new C);
f(new D);
f(new E);
?>
Приклад #4 Оголошення базового типу інтерфейсу
<?php
interface I { public function f(); }
class C implements I { public function f() {} }
// This doesn't implement I.
class E {}
function f(I $i) {
echo get_class($i)."\n";
}
f(new C);
f(new E);
?>
Приклад #5 Оголошення базового типу повернення
<?php
function sum($a, $b): float {
return $a + $b;
}
// Note that a float will be returned.
var_dump(sum(1, 2));
?>
Приклад #6 Повернення об'єкту
<?php
class C {}
function getC(): C {
return new C;
}
var_dump(getC());
?>
Приклад #7 Оголошення нульового типу аргументу
<?php
class C {}
function f(?C $c) {
var_dump($c);
}
f(new C);
f(null);
?>
Приклад #8 Оголошення нульового типу повернення
<?php
function get_item(): ?string {
if (isset($_GET['item'])) {
return $_GET['item'];
} else {
return null;
}
}
?>
За замовчуванням PHP примусово підставляє значення неправильного типу в очікуване оголошення скалярного типу, якщо це можливо. Наприклад, функція, яка отримує параметр типу int, а очікується, що це буде рядок, отримає змінну типу string.
Строгий режим можна увімкнути для кожного окремого файлу. У строгому режимі буде прийнято лише значення, що точно відповідає оголошенню типу, інакше буде згенеровано помилку TypeError. Єдиним винятком з цього правила є ситуація, коли значення типу int буде передано з оголошенням типу float.
Виклики функцій із внутрішніх функцій не впливатимуть на оголошення strict_types.
Щоб увімкнути строгий режим, використовується інструкція declare з оголошенням strict_types:
Зауважте:
Сувора типізація застосовується до викликів функцій, зроблених з файлу з увімкненою суворою типізацією, а не до функцій, оголошених у цьому файлі. Якщо файл без увімкненої суворої типізації викликає функцію, яка була визначена у файлі із суворою типізацією, то буде враховано уподобання користувача (примусова типізація) і значення буде примусово присвоєно.
Зауважте:
Сувора типізація визначена лише для оголошень скалярних типів.
Приклад #9 Сувора типізація для значень аргументів
<?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));
?>
Приклад #10 Примусове введення значень аргументів
<?php
function sum(int $a, int $b) {
return $a + $b;
}
var_dump(sum(1, 2));
// These will be coerced to integers: note the output below!
var_dump(sum(1.5, 2.5));
?>
Приклад #11 Сувора типізація для значень, що повертаються
<?php
declare(strict_types=1);
function sum($a, $b): int {
return $a + $b;
}
var_dump(sum(1, 2));
var_dump(sum(1, 2.5));
?>