• Час читання ~3 хв
  • 28.03.2023

З виходом PHP 8.1 мова отримала нативну підтримку enums. Enums - це безпечний, читабельний та ефективний спосіб інкапсуляції невеликого набору можливих значень, які поле може прийняти у вашій моделі даних. Використання класів замість енумів бази даних забезпечує більшу гнучкість, якщо вам потрібно буде додати до списку в майбутньому.

Наприклад, у вас є модель даних користувача, і цей користувач може мати певний список ролей, з яких ви можете вибрати.

namespace App\Enums;

enum UserRole: string
{
    case Admin = 'admin';
    case TeamAdmin = 'team_admin';
    case Support = 'support';
    case Basic = 'basic';
}

У вашій моделі даних Laravel також має підтримку енумів, переводячи їх у значення, якщо ви визначаєте його у своєму масиві кастів.

/**
 * The attributes that should be cast.
 *
 * @var array<string,string|class-string>
 */
protected $casts = [
    'role' => UserRole::class,
];

Додавання кастингу enum гарантує, що виняток буде кинуто, якщо ми спробуємо зберегти роль для нашої моделі користувача, не визначеної в enum.

Дуже практичне використання enums полягає в тому, щоб генерувати значення для спадного меню у вашому HTML

<select name=”roles”>
    @foreach(UserRole::cases() as $role)
        <option value="{{ $role->value }}">{{ $role->name }}</option>
    @endforeach
</select>

На поверхні нічого поганого в прикладі вище не здається, поки ви не подивитеся на видиме ім'я кожного параметра у спадному меню. Admin і TeamAdmin - це чудові імена змінних, але адміністратору та адміністратору команди було б краще представити в інтерфейсі користувача, тому абсолютно зрозуміло, яка роль для людини, яка керує ролями користувачів.

Хоча enums чудово підходять для простих пар ім'я/значення, у таких випадках, коли вам потрібно додати 3-ю властивість, ви повинні проявити креативність.

Введіть атрибути PHP. Запозичений з поняття анотації в інших мовах, це спосіб пов'язати метадані з властивостями, методами і класами, що звучить точно так само, як і те, що нам потрібно.

По-перше, нам потрібно побудувати атрибут Опис.

namespace App\Enums\Attributes;

use Attribute;

#[Attribute]
class Description
{
    public function __construct(
            public string $description,
    ) {
    }
}

Тепер у нас є атрибут Опис, який ми можемо використовувати в нашому enum, щоб ми могли визначити зручні імена ролей, які ми бажаємо.

namespace App\Enums;

enum UserRole: string
{
    #[Description('Administrator')]
    case Admin = 'admin';

    #[Description('Team Administrator')]
    case TeamAdmin = 'team_admin';

    case Support = 'support';
    case basic = 'basic';
}

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

namespace App\Enums\Concerns;

use Illuminate\Support\Str;
use ReflectionClassConstant;
use App\Enums\Attributes\Description;

trait GetsAttributes
{
    /**
     * @param self $enum
     */
    private static function getDescription(self $enum): string
    {
        $ref = new ReflectionClassConstant(self::class, $enum->name);
        $classAttributes = $ref->getAttributes(Description::class);

        if (count($classAttributes) === 0) {
                return Str::headline($enum->value);
        }
        return $classAttributes[0]->newInstance()->description;
    }
}

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

Нарешті, витягнемо значення опису з атрибутів enum. Ми можемо додати ще один метод до нашої риси, щоб впоратися з цим.

/**
 * @return array<string,string>
 */
public static function asSelectArray(): array
{
    /** @var array<string,string> $values */
    $values = collect(self::cases())
        ->map(function ($enum) {
            return [
                'name' => self::getDescription($enum),
                'value' => $enum->value,
            ];
        })->toArray();

    return $values;
}

Тепер у нашому HTML ми можемо просто змінити метод, який ми викликаємо для класу

<select name=”roles”>
       @foreach(UserRoles::asSelectArray() as $role)
            <option value=”{{ $role->value }}”>{{ $role->name }}</option>
       @endforeach
</select>

enum Хоча вони є відносними новачками в PHP, enums та атрибути є чудовим доповненням до мови та забезпечують нативну підтримку багатьох поширених випадків використання.

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