• Czas czytania ~3 min
  • 28.03.2023

Wraz z wydaniem PHP 8.1 język zyskał natywne wsparcie dla wyliczeń. Wyliczenia to bezpieczny dla typu, czytelny i wydajny sposób hermetyzacji małego zestawu możliwych wartości, które pole może przyjąć w modelu danych. Używanie klas zamiast wyliczeń bazy danych zapewnia większą elastyczność, jeśli w przyszłości trzeba dodać do listy.

Na przykład masz model danych użytkownika, który może mieć określoną listę ról, z których możesz wybierać.

namespace App\Enums;

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

W modelu danych Laravel obsługuje również wyliczenia, rzutując je na wartość, jeśli zdefiniujesz ją w tablicy rzutów.

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

Dodanie rzutowania wyliczenia zapewni, że wyjątek zostanie wygenerowany, jeśli spróbujemy zapisać rolę w naszym modelu użytkownika, który nie został zdefiniowany w wyliczeniu.

Bardzo praktycznym zastosowaniem wyliczeń jest generowanie wartości dla listy rozwijanej w kodzie HTML

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

Na pierwszy rzut oka nic nie wydaje się złe w powyższym przykładzie, dopóki nie spojrzysz na widoczną nazwę każdej opcji z listy rozwijanej. Admin i TeamAdmin to świetne nazwy zmiennych, ale Administrator i Team Administrator lepiej byłoby przedstawić w interfejsie użytkownika, więc jest krystalicznie jasne, jaka jest rola dla osoby zarządzającej rolami użytkowników.

Podczas gdy wyliczenia świetnie nadają się do prostych par nazwa / wartość, w takich przypadkach, gdy musisz dodać 3. właściwość, musisz wykazać się kreatywnością.

Wprowadź atrybuty PHP. Zapożyczony z koncepcji adnotacji w innych językach, jest to sposób na powiązanie metadanych z właściwościami, metodami i klasami, co brzmi dokładnie tak, jak potrzebujemy.

Najpierw musimy zbudować atrybut Opis.

namespace App\Enums\Attributes;

use Attribute;

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

Mamy teraz atrybut Opis, który możemy wykorzystać w naszym wyliczeniu, abyśmy mogli zdefiniować przyjazne dla użytkownika nazwy ról, których szukamy.

namespace App\Enums;

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

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

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

Teraz musimy odzyskać te atrybuty, co można zrobić tylko poprzez refleksję. Ponieważ możemy chcieć ponownie użyć tego atrybutu na innych wyliczeniach, będziemy chcieli stworzyć cechę, która to ułatwi

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;
    }
}

. Jeśli podzielimy tę metodę, pierwsze 2 linie używają odbicia, aby uzyskać atrybuty wyliczenia. Ponieważ nie każdy wyliczenie może mieć atrybut Opis, ustawiamy rezerwę, aby przekształcić wartość (lub nazwę) tego wyliczenia jako nasz opis.

Na koniec pobieramy wartość opisu z atrybutów wyliczenia. Możemy dodać inną metodę do naszej cechy, aby sobie z tym poradzić.

/**
 * @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;
}

Teraz, w naszym HTML, możemy po prostu zmienić metodę, którą wywołujemy w klasie enum Chociaż są względnymi nowicjuszami w

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

PHP, wyliczenia i atrybuty są świetnymi dodatkami do języka i zapewniają natywne wsparcie dla wielu typowych przypadków użycia.

Comments

No comments yet
Yurij Finiv

Yurij Finiv

Full stack

O

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...

O autorze CrazyBoy49z
WORK EXPERIENCE
Kontakt
Ukraine, Lutsk
+380979856297