• Час читання ~5 хв
  • 07.03.2023

Використовуєте застарілий додаток Laravel? Отримайте миттєві, автоматизовані оновлення Laravel за допомогою Laravel Shift

Вони нарешті з'являться — вбудована підтримка перерахувань буде додана в PHP 8.1! Дехто може вважати їх давно назрілими, але ви не чуєте, як я скаржуся; Я радий, що їм це вдалося! Ця публікація присвячена поглибленому розгляду нещодавно доданої функції. Якщо ви хочете бути в курсі таких змін та нових функцій у PHP, обов'язково підпишіться на мій інформаційний бюлетень.

Як завжди з моїми публікаціями функцій PHP, ми починаємо з огляду високого рівня того, як виглядають перерахування:Перевага enums полягає в тому, що вони представляють набір постійних значень, але найголовніше, що ці значення можна ввести, наприклад:

enum Status
{
    case DRAFT;
    case PUBLISHED;
    case ARCHIVED;
}

У цьому прикладі створення enum і передача його в a BlogPost виглядає так:

class BlogPost
{
    public function __construct(
        public Status $status, 
    ) {}
}

$post = new BlogPost(Status::DRAFT);

Це основи, як бачите, в них взагалі немає нічого складного. Однак є багато побічних приміток, давайте подивимося на перерахування глибоко!

# Методи

Enum Enums можуть визначати методи, як і класи. Це дуже потужна функція, особливо в поєднанні з операторомmatch:Методи можна використовувати так:Статичні методи також дозволені:І ви також можете використовувати self в межах enum:# Інтерфейси Enum Enums можуть реалізовувати інтерфейси

enum Status
{
    case DRAFT;
    case PUBLISHED;
    case ARCHIVED;
    
    public function color(): string
    {
        return match($this) 
        {
            Status::DRAFT => 'grey',   
            Status::PUBLISHED => 'green',   
            Status::ARCHIVED => 'red',   
        };
    }
}

, як і звичайні класи:

$status = Status::ARCHIVED;
$status->color(); // 'red'

enum Status
{
    // …
    
    public static function make(): Status
    {
        // …
    }
}

enum Status
{
    // …
    
    public function color(): string
    {
        return match($this) 
        {
            self::DRAFT => 'grey',   
            self::PUBLISHED => 'green',   
            self::ARCHIVED => 'red',   
        };
    }
}

interface HasColor
{
    public function color(): string;
}
enum Status implements HasColor
{
    case DRAFT;
    case PUBLISHED;
    case ARCHIVED;
    
    public function color(): string { /* … */ }
}

# Значення Enum — aka "Backed enums"

Значення Enum представлені внутрішніми об'єктами, але ви можете призначити їм значення, якщо хочете; Це корисно для напр. серіалізація їх у базу даних.

enum Status: string
{
    case DRAFT = 'draft';
    case PUBLISHED = 'published';
    case ARCHIVED = 'archived';
}

Зверніть увагу на декларацію типу у визначенні enum. Він вказує на те, що всі значення enum відносяться до заданого типу. Ви також можете зробити це .int Зверніть увагу, що тільки int і string дозволені як значення enum.

enum Status: int
{
    case DRAFT = 1;
    case PUBLISHED = 2;
    case ARCHIVED = 3;
}

Технічний термін для типізованих енумів називається "backed enums", оскільки вони "підкріплені" простішим значенням. Якщо ви вирішили призначити значення enum, всі регістри повинні мати значення. Змішувати і поєднувати їх не можна. Перерахування, які не є «підкріпленими», називаються «чистими перерахуваннями».

# Резервні перерахування з інтерфейсами

Якщо ви поєднуєте резервні перерахування та інтерфейс, тип enum має стояти безпосередньо після імені enum, перед ключовим словомimplements.

enum Status: string implements HasColor
{
    case DRAFT = 'draft';
    case PUBLISHED = 'published';
    case ARCHIVED = 'archived';
    
    // …
}

# Серіалізація резервних перерахувань Якщо

ви призначаєте значення регістрам enum, вам, ймовірно, потрібен спосіб їх серіалізації та десеріалізації. Серіалізація їх означає, що вам потрібен спосіб отримати доступ до значення enum. Це робиться з публічною властивістю readonly:Відновлення enum зі значення можна виконати за допомогою Enum::from:

$value = Status::PUBLISHED->value; // 2

$status = Status::from(2); // Status::PUBLISHED

Також є a tryFrom який повертаєтьсяnull, якщо передається невідоме значення. Якщо ви будете використовуватиfrom, буде виняток.

$status = Status::from('unknown'); // ValueError
$status = Status::tryFrom('unknown'); // null

Зверніть увагу, що ви також можете використовувати вбудовані serialize функції unserialize і функції на enums. Крім того, ви можете використовувати json_encode в поєднанні з резервними енумами, його результатом буде значення enum. Цю поведінку можна подолати, реалізувавши JsonSerializable.

# Лістинг значень

enum Ви можете використовувати статичний Enum::cases() метод, щоб отримати список усіх доступних випадків в enum:Зверніть увагу, що цей масив містить фактичні об'єкти enum:

Status::cases();
/* [
    Status::DRAFT, 
    Status::PUBLISHED, 
    Status::ARCHIVED
] */

array_map(
    fn(Status $status) => $status->color(), 
    Status::cases()
);

# Enums - це об'єкти Я вже згадував, що значення enums представлені як об'єкти, насправді це одиночні об'єкти

. Це означає, що ви можете робити порівняння з ними так:

$statusA = Status::PENDING;
$statusB = Status::PENDING;
$statusC = Status::ARCHIVED;
$statusA === $statusB; // true
$statusA === $statusC; // false
$statusC instanceof Status; // true

# Перерахування як ключі масиву Оскільки значення enums насправді є об'єктами, наразі їх неможливо використовувати як ключі масиву

. Помилка призведе до наступного:

$list = [
    Status::DRAFT => 'draft',
    // …
];

RFC змінить цю поведінку, але він ще не проголосований.

Це означає, що ви можете використовувати enums лише як ключі в SplObjectStorage та WeakMaps.

# Риси характеру Enums можуть використовувати риси

так само, як класи, але з деякими іншими обмеженнями. Вам заборонено перевизначати вбудовані методи enum, і вони не можуть містити властивості класів — вони заборонені для enums.

# Відображення та атрибути

Як і очікувалося, додано кілька класів відображення для роботи з енумами: ReflectionEnum, ReflectionEnumUnitCase і ReflectionEnumBackedCase. Також з'явилася нова enum_exists функція, яка робить те, що випливає з її назви.

Так само, як і звичайні класи та властивості, enums та їх відмінки можуть бути анотовані за допомогою атрибутів. Зауважте, що TARGET_CLASS фільтр також міститиме перерахування.

І останнє: enums також мають властивість $enum->nameтільки для читання , яка, згадана RFC, є деталлю реалізації і, ймовірно, повинна використовуватися тільки для цілей налагодження. Однак це все ж варто згадати.

Помітили tpyo? Ви можете подати PR, щоб виправити це. Якщо ви хочете бути в курсі того, що відбувається в цьому блозі, ви можете слідкувати за мною у Twitter або підпишіться на мою розсилку:

Це приблизно все, що можна сказати про перерахування, я дуже чекаю їх використання, як тільки з'явиться PHP 8.1, а також щоб закрити мою власну реалізацію користувача.

Comments

No comments yet
Yurij Finiv

Yurij Finiv

Full stack

Про мене

Professional Fullstack Developer with extensive experience in website and desktop application development. Proficient in a wide range of tools and technologies, including Bootstrap, Tailwind, HTML5, CSS3, PUG, JavaScript, Alpine.js, jQuery, PHP, MODX, and Node.js. Skilled in website development using Symfony, MODX, and Laravel. Experience: Contributed to the development and translation of MODX3 i...

Про автора CrazyBoy49z
WORK EXPERIENCE
Контакти
Ukraine, Lutsk
+380979856297