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.
- Tip güvenliği ve okunabilirlik kazanırsınız.
intyerineOrderStatus $statusimzası 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. - Davranış değerle birlikte yaşar. Enum’a
->label(),->isFinal(),->canTransitionTo()gibi metotlar koyabilirsiniz. Böylece kod tabanına yayılmış onlarcaswitch/matchbloğu tek bir yere toplanır — asıl bakım kazancı buradadır. - Backed enum DB ve serialization uyumunu korur.
enum OrderStatus: intaynı integer değerlerini taşıdığı sürece DB kolonu da JSON çıktısı da değişmez. Göçü güvenli yapan tam olarak budur; kolonuvarchar’a çevirmeye kalkmayın. - Bedeli sınırlardaki hidrasyondur. DB’den veya request’ten gelen ham int’i
OrderStatus::from()ile cast etmeniz gerekir vefrom()bilinmeyen değerde exception fırlatır. Eskiden sessizce geçen bozuk/legacy bir status artık patlar — güvenilmez sınırlardatryFrom()kullanıpnulldurumunu ele alın. - 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.
- 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
Yorumlar
Yorum yapmak için GitHub hesabınızla giriş yapmanız yeterli. Yorumlar GitHub Discussions üzerinde saklanır.