İçeriğe geç
Muhammet Şafak
en
Soran: Mert Cevaplandı:

PHP durum sabitlerimi backed enum'a taşımak kod tabanıma ne kazandırır, neyi zorlaştırır?


Soru

Eski bir sipariş modülünde onlarca `const STATUS_PENDING = 1`, `const STATUS_PAID = 2` tarzı integer sabiti dolaşıyor. Bu sabitler kontrolcülerden servislere, event listener'lara kadar her yere yayılmış durumda ve durum kontrolleri de irili ufaklı `switch` blokları hâlinde tekrar ediyor. PHP 8.2 ve Laravel 11 kullanıyorum. Bu sabitleri yardımcı metotları olan bir backed enum'a taşımayı düşünüyorum. Bu geçiş bana gerçekte ne kazandırır, neyi zorlaştırır ve DB'deki mevcut integer değerlerini bozmadan bunu nasıl yaparım?

Cevap

Kısa cevap: Hâlâ aktif dokunduğunuz bir modül için bu geçiş net kazançtır — ama bedava değildir ve big-bang bir rewrite olmamalıdır.

Enum’lar sihirli değnek değil; sabitlere göre neyi değiştirdiklerini bilerek girmezseniz, kazandığınız tip güvenliğini sınırlarda patlayan hatalarla geri ödersiniz.

  1. Tip güvenliği ve okunabilirlik kazanırsınız. int yerine OrderStatus $status imzası hem niyeti anlatır hem de PHPStan/Psalm’ın geçersiz değeri kod çalışmadan yakalamasını sağlar; IDE autocomplete tüm case’leri size verir. Ham sabitlerle bunların hiçbiri mümkün değildir.
  2. Davranış değerle birlikte yaşar. Enum’a ->label(), ->isFinal(), ->canTransitionTo() gibi metotlar koyabilirsiniz. Böylece kod tabanına yayılmış onlarca switch/match bloğu tek bir yere toplanır — asıl bakım kazancı buradadır.
  3. Backed enum DB ve serialization uyumunu korur. enum OrderStatus: int aynı integer değerlerini taşıdığı sürece DB kolonu da JSON çıktısı da değişmez. Göçü güvenli yapan tam olarak budur; kolonu varchar’a çevirmeye kalkmayın.
  4. Bedeli sınırlardaki hidrasyondur. DB’den veya request’ten gelen ham int’i OrderStatus::from() ile cast etmeniz gerekir ve from() bilinmeyen değerde exception fırlatır. Eskiden sessizce geçen bozuk/legacy bir status artık patlar — güvenilmez sınırlarda tryFrom() kullanıp null durumunu ele alın.
  5. Enum genişletilemez. Runtime’da case eklenemez, inheritance yoktur, dinamik instantiation yapılamaz. Tenant’a özel dinamik durumlar gerekiyorsa enum yanlış araçtır; orada bir lookup tablosu daha doğrudur.
  6. Göç kademeli olmalı. Enum’u sabitlerin yanına koyun, eski sabitleri bir sürüm boyunca deprecated alias olarak tutun, çağrı yerlerini parça parça taşıyın. Laravel’de Eloquent’in native enum cast’i işin büyük kısmını halleder.
enum OrderStatus: int
{
    case Pending = 1;
    case Paid = 2;
    case Shipped = 3;
    case Cancelled = 9;

    public function isFinal(): bool
    {
        return in_array($this, [self::Shipped, self::Cancelled], true);
    }
}

// Eloquent modelinde:
protected $casts = ['status' => OrderStatus::class];

Sonuç: Ben olsam kademeli giderdim — aynı integer değerleriyle backed enum, sınırlarda tryFrom(), eski sabitler bir sürüm boyunca deprecated alias olarak. Önce enum’u ekleyip Eloquent cast’ini bağlar, sonra bir PR’da bir servis olacak şekilde çağrı yerlerini taşırdım. Riskli olan tek nokta legacy verideki “yetim” status değerleridir; onları göçten önce bir SELECT DISTINCT status ile taradığınızda geçiş sizi hiç şaşırtmaz.

İlgili Yazılar

Etiketler: #php#enum#refactoring
Paylaş:

Yorumlar

Yorum yapmak için GitHub hesabınızla giriş yapmanız yeterli. Yorumlar GitHub Discussions üzerinde saklanır.

Diğer Sorular

Tüm sorular

Sitede Ara

Yazı, proje ve sayfalarda arama yapmak için yazmaya başlayın.

Esc ile kapat Pagefind ile güçlendirildi