Backed enumerations

Оновлено: 09.05.2023

За замовчуванням, перелічені випадки не мають скалярного еквівалента. Це просто одиночні об'єкти. Однак існує багато випадків, коли перелічуваний випадок повинен мати можливість звертатися до бази даних або подібного сховища даних, тому наявність вбудованого скалярного (а отже, тривіально серіалізованого) еквівалента, визначеного внутрішньо, є корисною.

Щоб визначити скалярний еквівалент для перечислення, синтаксис є наступним:

<?php
enum Suit: string
{
    case Hearts = 'H';
    case Diamonds = 'D';
    case Clubs = 'C';
    case Spades = 'S';
}
?>

Відмінок, який має скалярний еквівалент, називається "підкріпленим", оскільки він "підкріплений" простішим значенням. Перелік, який містить усі підкріплені випадки, називається "Підкріпленим переліком". Підкріплене зчислення може містити лише підкріплені випадки. Чисте зчислення може містити тільки чисті випадки.

Підтримуване зчислення може підтримувати типи int або string, і дане зчислення підтримує тільки один тип за раз (тобто не може бути об'єднання int|string). Якщо зчислення позначено як таке, що має скалярний еквівалент, то у всіх випадках повинен бути визначений унікальний скалярний еквівалент. Автоматично згенерованих скалярних еквівалентів (наприклад, послідовних цілих чисел) не існує. Підтримувані випадки повинні бути унікальними; два підтримувані випадки перечислення не можуть мати однаковий скалярний еквівалент. Однак, константа може посилатися на регістр, фактично створюючи псевдонім. Див. статтю Константи перечислення.

Еквівалентні значення повинні бути літералами або літеральними виразами. Константи та константні вирази не підтримуються. Тобто, 1 + 1 дозволено, але 1 + SOME_CONST - ні.

Backed Case має додаткову властивість, доступну лише для читання, value, яка є значенням, вказаним у визначенні.

<?php
print Suit::Clubs->value;
// Prints "C"
?>

Для того, щоб зробити властивість value доступною тільки для читання, змінній не можна присвоювати посилання на неї. Тобто, наступне призведе до помилки:

<?php
$suit = Suit::Clubs;
$ref = &$suit->value;
// Error: Cannot acquire reference to property Suit::$value
?>

Підтримувані зчислення реалізують внутрішній інтерфейс BackedEnum, який надає два додаткові методи:

from(int|string): self візьме скаляр і поверне відповідний перечислювальний регістр Enum Case. Якщо його не буде знайдено, буде згенеровано ValueError. Це переважно корисно у випадках, коли вхідному скаляру довіряють і відсутнє значення перечислення слід вважати помилкою, що зупиняє роботу програми. tryFrom(int|string): ?self прийме скаляр і поверне відповідний йому регістр перечислення. Якщо його не буде знайдено, буде повернуто нуль. Це переважно корисно у випадках, коли вхідний скаляр є ненадійним і користувач хоче реалізувати власну логіку обробки помилок або значення за замовчуванням.

Методи from() і tryFrom() слідують стандартним правилам слабкої/сильної типізації. У режимі слабкої типізації допустимо передавати ціле число або рядок, і система примусово перетворить значення відповідно. Передача числа з плаваючою комою також спрацює і буде перетворена. У режимі суворої типізації передача цілого числа до from() у зчислення з підтримкою рядка (або навпаки) призведе до TypeError, так само як і передача числа з плаваючою комою за будь-яких обставин. Всі інші типи параметрів призведуть до витоку помилки типу в обох режимах.

<?php
$record = get_stuff_from_database($id);
print $record['suit'];

$suit =  Suit::from($record['suit']);
// Invalid data throws a ValueError: "X" is not a valid scalar value for enum "Suit"
print $suit->value;

$suit = Suit::tryFrom('A') ?? Suit::Spades;
// Invalid data returns null, so Suit::Spades is used instead.
print $suit->value;
?>

Ручне визначення методу from() або tryFrom() для Backed Enum призведе до фатальної помилки.