PHP 8.1 Enums

·

7 min read

Sonunda geliyorlar - Enums için yerleşik destek PHP 8.1'de olacak! Birçoğumuz haklı olarak çok gecikmiş bir özellik olduğunu düşünebiliriz, ama şikayet etmeye gerek yok; Başardıklarına sevinmek gerek! Bu yazıda, yeni eklenen enum özelliğinee derinlemesine bakacağız.

Genel syntax şu şekilde olacak.Gayet bilindik :)

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

Enumların yararı, sabit değerlerin bir koleksiyonunu temsil etmeleridir, ancak en önemlisi bu değerler şöyle yazılabilir:

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

Bu örnekte, enum oluşturmak ve bunu bir BlogPost'a aktarmak aşağıdaki gibi yazılabilir:

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

Bunların hiçbirinde karmaşık bir şey olmadığını görebileceğiniz için, yolun dışında kalan temel hususlar budur. Yine de uygulanması gereken çok sayıda yan not var, hadi Enum'lara derinlemesine bakalım!

Enum methodları

Enum'lar, tıpkı class'daki method yapıları gibi tanımlanabilir. Bu, özellikle match operatörü ile birlikte kullanıldığında çok güçlü bir özelliktir:

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

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

Methodlar şu şekilde kullanılabilir:

$status = Status::ARCHIVED;

$status->color(); // 'red'

Statik metodlara da izin veriliyor:

enum Status
{
    // …

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

Ayrıca self çağrısını bir enum içinde de kullanabilirsiniz:

enum Status
{
    // …

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

Enum Interface Yapısı Enumlar, normal classlar gibi interfacelere uygulanabilirler:

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

    public function color(): string { /* … */ }
}

Enum değerleri — diğer bir deyişle "Backed enums"

Enum değerleri nesneler tarafından dahili olarak temsil edilir, ancak isterseniz bunlara bir değer atayabilirsiniz;

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

Enum tanımındaki tür bildirimine(type declaration) dikkat edin. Tüm enum değerlerinin belirli bir türde olduğunu belirtir. Bunu bir int de yapabilirsiniz. Şu anda enum dönüşüm tipleri anlamında yalnızca int ve string tiplerine izin veriliyor.

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

Enum için teknik terim, daha basit bir değerle "desteklendikleri" için "yedeklenmiş Enumlar" olarak adlandırılır. Enum değerleri atamaya karar verirseniz, tüm servis taleplerinin bir değeri olmalıdır. Onları karıştırıp eşleştiremezsiniz. "Desteklenmeyen" Enumlara "saf enumlar" denir.

Interfacelere dayalı Backed enumlar

Backed enum yapıları ile interface birleştiriyorsanız, enum türü, anahtar sözcüğünü uygulamadan önce, enum adından hemen sonra gelmelidir.Biraz kafa karıştırıcı oldu:)

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

    // …
}

Backed enumları serialize etmek

Enum durumlarına değerler atıyorsanız, muhtemelen onları serialize/deserialize etmenin bir yolunu anlamak isteyebilirsiniz. Bunları serileştirmek, enumun değerine erişmenin bir yoluna ihtiyacınız olduğu anlamına gelir. Bu, salt okunur bir public property erişimi ile yapılır:

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

Bir değerden bir enum geri yüklemek için Enum :: from kullanılabilir:

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

Ayrıca bilinmeyen bir değer iletilirse null döndüren bir tryFrom kullanılabilir, from kullanırsanız bir exception oluşabilir.

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

PHP ile birlikte gelen(built-in) serialize ve unserialize methodlarını kullanarak Enumlar üzerinde serileştirme işlevlerini de kullanabileceğinizi unutmayın. Ayrıca, json_encode metodunu backed enumlar ile birlikte kullanabilirsiniz, dönüş değeri enum değeri olacaktır. Bu davranış, JsonSerializable uygulanarak geçersiz kılınabilir.

Enum değerlerini listemelek

Bir enum içindeki tüm kullanılabilir durumların bir listesini almak için statik Enum :: Cases () metodunu kullanabilirsiniz:

Status::cases();

/* [
    Status::DRAFT, 
    Status::PUBLISHED, 
    Status::ARCHIVED
] */

Enumlar da Objedir

Enum değerlerinin nesneler olarak temsil edildiğinden bahsetmiştim, aslında bunlar tek nesnelerdir. Bu da demek oluyor ki onlarla şu şekilde karşılaştırmalar yapabileceğiz:

$statusA = Status::PENDING;
$statusB = Status::PENDING;
$statusC = Status::ARCHIVED;

$statusA === $statusB; // true
$statusA === $statusC; // false
$statusC instanceof Status; // true

Dizi anahtarı olarak enumlar

Enum değerleri aslında nesneler olduğundan, bunları dizi anahtarları olarak kullanmak şu anda mümkün değil. Aşağıdaki ifadeler bir hatayla sonuçlanacaktır:

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

Bu davranışı değiştirecek bir RFC var, ancak henüz oylanmadı.

Bu, Enumları yalnızca SplObjectStorage ve WeakMaps'te anahtar olarak kullanabileceğiniz anlamına gelir.

Traitler

Enumlar, traitleri tıpkı sınıflar gibi kullanabilir, ancak daha fazla kısıtlama ile. Built-in enum metodlarını geçersiz kılmanıza(override) izin verilmez ve bunlar class özelliklerini içeremez - bunlar enumda yasaktır.

Reflection ve attribute'lar

Beklendiği gibi, enumlarla uğraşmak için eklenen birkaç reflection sınıfı vardır: ReflectionEnum, ReflectionEnumUnitCase ve ReflectionEnumBackedCase. Adından da anlaşılacağı gibi yeni bir enum_exists işlevi de var.

Normal class ve propertyler gibi, enumlar ve bunların durumları attribute kullanılarak açıklanabilir. TARGET_CLASS filtresinin enumları da içereceğini unutmayın.