Laravel’de enum kullanmaya başlayınca ilk karşılaşılan kavramlardan biri şu oluyor:
Backed enum ne demek?
İlk bakışta biraz “fazla akademik” gibi duran bir terim. Ama aslında olay oldukça basit:
Backed enum, her enum case’inin arkasında gerçek bir string veya int değer taşıdığı enum türüdür.
Yani enum sadece PHP tarafında sembolik bir isimden ibaret değildir; aynı zamanda veritabanına yazılabilecek, request’ten gelebilecek veya API response’unda kullanılabilecek gerçek bir değere sahiptir.
Bu yazıda Laravel üzerinden backed enum mantığını, pure enum’dan farkını ve günlük projelerde nasıl kullanılacağını anlatacağım.
Enum nedir?
Enum, belirli bir alanın alabileceği değerleri kontrollü hale getiren bir yapıdır.
Mesela bir kullanıcı rolü düşünelim:
admin
editor
user
Normalde bunları string olarak kullanabiliriz:
if ($user->role === 'admin') {
// ...
}
Ama bu kullanımın birkaç problemi var:
- Yazım hatalarına açık.
- Her yerde string tekrar ediyor.
- IDE desteği zayıf.
- Refactor yapmak zorlaşıyor.
- Sistemde hangi roller var, tek bir yerden anlaşılmıyor.
Enum ile bu değerleri tek bir yerde toplarız:
namespace App\Enums;
enum UserRole: string
{
case Admin = 'admin';
case Editor = 'editor';
case User = 'user';
}
Artık rol kontrolünü şöyle yapabiliriz:
if ($user->role === UserRole::Admin) {
// ...
}
Bu hem daha okunabilir hem de daha güvenli.
Pure Enum ve Backed Enum farkı
PHP’de temel olarak iki enum türü var:
- Pure enum
- Backed enum
Laravel’de de aslında bu PHP enum’larını kullanıyoruz. Laravel burada enum’ları model cast, validation ve request işlemlerinde daha pratik hale getiriyor.
Pure Enum nedir?
Pure enum, case’lerin arkasında herhangi bir değer taşımadığı enum türüdür.
enum UserRole
{
case Admin;
case Editor;
case User;
}
Burada Admin, Editor ve User sadece enum case’leridir.
Şunu yapabiliriz:
$role = UserRole::Admin;
Ama şunu yapamayız:
UserRole::Admin->value;
Çünkü pure enum’da value yoktur.
Sadece name vardır:
UserRole::Admin->name; // "Admin"
Pure enum daha çok uygulama içinde sembolik durumları belirtmek için kullanılabilir. Fakat veritabanına değer yazmak istediğimiz senaryolarda genellikle yeterli olmaz.
Backed Enum nedir?
Backed enum’da her case’in arkasında gerçek bir değer bulunur.
Bu değer yalnızca iki tür olabilir:
string
int
Örneğin:
namespace App\Enums;
enum UserRole: string
{
case Admin = 'admin';
case Editor = 'editor';
case User = 'user';
}
Burada enum case’i şudur:
UserRole::Admin
Bu case’in arkasındaki gerçek değer ise şudur:
UserRole::Admin->value; // "admin"
Yani:
case Admin = 'admin';
satırında iki farklı şey var:
UserRole::Admin->name; // "Admin"
UserRole::Admin->value; // "admin"
name, PHP tarafındaki case adıdır.
value, dış dünyaya veya veritabanına yazılacak gerçek değerdir.
Backed enum neden Laravel’de daha çok kullanılır?
Çünkü Laravel projelerinde enum kullandığımız alanların çoğu veritabanıyla ilişkilidir.
Örneğin:
rolestatustypepayment_statusorder_statusnotification_channelprovider
Bu alanların veritabanında bir karşılığı vardır.
Mesela users tablosunda şöyle bir değer tutmak isteriz:
role = admin
Ama PHP tarafında bu değeri düz string olarak kontrol etmek yerine enum olarak kullanmak isteriz:
$user->role === UserRole::Admin
İşte backed enum burada çok işe yarar.
Laravel’de enum dosyası oluşturmak
Laravel’de enum oluşturmak için Artisan komutu kullanılabilir:
php artisan make:enum Enums/UserRole
Bu komutla enum dosyasını app/Enums/UserRole.php altında tutabiliriz.
Örnek enum:
namespace App\Enums;
enum UserRole: string
{
case Admin = 'admin';
case Editor = 'editor';
case User = 'user';
}
Ben genelde enum’ları app/Enums klasörü altında tutmayı daha düzenli buluyorum. Çünkü proje büyüdükçe enum sayısı artıyor ve bunların app dizininin altında dağınık durması pek hoş olmuyor.
Laravel model cast ile kullanım
Enum’un en güzel taraflarından biri, Laravel model cast ile çok temiz çalışmasıdır.
Örneğin users tablosunda role alanımız olsun.
Migration tarafında bunu basit bir string kolon olarak tutabiliriz:
$table->string('role')->default(UserRole::User->value);
Modelde ise cast tanımlarız:
use App\Enums\UserRole;
protected function casts(): array
{
return [
'role' => UserRole::class,
];
}
Bundan sonra Laravel, veritabanındaki string değeri otomatik olarak enum’a çevirir.
Yani veritabanında şu varsa:
role = admin
Modelde şunu elde ederiz:
$user->role; // UserRole::Admin
Artık kontrolü şöyle yapabiliriz:
if ($user->role === UserRole::Admin) {
// Admin işlemleri
}
Kaydetmek de oldukça temizdir:
$user->role = UserRole::Editor;
$user->save();
Laravel bunu veritabanına otomatik olarak şöyle yazar:
editor
Burada bizim manuel olarak ->value vermemize gerek kalmaz. Laravel enum cast sayesinde bunu bizim yerimize halleder.
Form request ve validation tarafı
Backed enum’ları request doğrulamada da kullanabiliriz.
use App\Enums\UserRole;
use Illuminate\Validation\Rule;
$request->validate([
'role' => ['required', Rule::enum(UserRole::class)],
]);
Bu sayede role alanı sadece enum içinde tanımlı değerlerden biri olabilir.
Yani şunlar geçerlidir:
admin
editor
user
Ama şu geçerli olmaz:
super_admin
Bu küçük gibi görünen şey aslında büyük projelerde ciddi fayda sağlar. Çünkü veri daha sisteme girerken kontrol altına alınır.
from() ve tryFrom() farkı
Backed enum’ların güzel özelliklerinden biri de string veya int değerden enum case’i oluşturabilmemizdir.
$role = UserRole::from('admin');
Bu bize şunu döndürür:
UserRole::Admin
Ama dikkat etmek gerekir. Eğer geçersiz bir değer verirsek:
UserRole::from('wrong-role');
PHP hata fırlatır.
Daha güvenli kullanım için tryFrom() tercih edilebilir:
$role = UserRole::tryFrom('admin');
Geçerli değer varsa enum case’i döner:
UserRole::Admin
Geçersiz değer varsa null döner:
$role = UserRole::tryFrom('wrong-role'); // null
Ben genelde dışarıdan gelen, güvenmediğim verilerde tryFrom() kullanmayı daha doğru buluyorum.
Enum içine yardımcı metotlar eklemek
Enum’lar sadece sabit değer listesi olmak zorunda değil. İçlerine metot da ekleyebiliriz.
Mesela kullanıcı rollerine ekranda gösterilecek label değerleri ekleyelim:
namespace App\Enums;
enum UserRole: string
{
case Admin = 'admin';
case Editor = 'editor';
case User = 'user';
public function label(): string
{
return match ($this) {
self::Admin => 'Yönetici',
self::Editor => 'Editör',
self::User => 'Kullanıcı',
};
}
}
Kullanım:
$user->role->label();
Bu şekilde enum sadece teknik değer tutmaz, aynı zamanda o değere ait davranışı da taşıyabilir.
Bu özellikle admin panel, select input, filtreleme ve raporlama gibi alanlarda çok işe yarar.
Select input için options üretmek
Enum’dan select option üretmek de güzel bir kullanım örneğidir.
public static function options(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $role) => [
$role->value => $role->label(),
])
->toArray();
}
Artık şunu yapabiliriz:
UserRole::options();
Çıktı:
[
'admin' => 'Yönetici',
'editor' => 'Editör',
'user' => 'Kullanıcı',
]
Bu yaklaşım sayesinde hem backend hem frontend tarafında aynı değerleri daha kontrollü kullanabiliriz.
Veritabanında SQL enum mu, string kolon mu?
Burada önemli bir tercih var.
MySQL tarafında gerçekten enum kolon tipi kullanabiliriz. Ama ben çoğu Laravel projesinde string kolon kullanmayı daha esnek buluyorum.
Örneğin:
$table->string('status');
Neden?
Çünkü enum değerleri zamanla değişebilir. Yeni bir status eklemek isteyebiliriz. SQL enum kullanırsak veritabanı şemasını değiştirmek gerekir. String kolon kullanıp uygulama tarafında PHP enum ile kontrol sağlamak genelde daha rahat bir yaklaşımdır.
Yani kontrolü database seviyesinde değil, uygulama seviyesinde enum ile sağlamış oluruz.
Bu her zaman tek doğru demek değil. Ama Laravel projelerinde çoğu senaryo için pratik ve sürdürülebilir bir tercih olduğunu düşünüyorum.
Ne zaman backed enum kullanmalıyız?
Şu tarz alanlarda backed enum oldukça mantıklıdır:
role
status
type
category
payment_status
order_status
provider
channel
visibility
priority
Mesela:
enum OrderStatus: string
{
case Pending = 'pending';
case Paid = 'paid';
case Shipped = 'shipped';
case Cancelled = 'cancelled';
}
Ya da:
enum PaymentStatus: string
{
case Waiting = 'waiting';
case Successful = 'successful';
case Failed = 'failed';
}
Bu tarz alanlarda backed enum kullanmak, magic string kullanımını ciddi ölçüde azaltır.
Ne zaman pure enum kullanılır?
Pure enum’u ise daha çok veritabanına yazılmayacak, sadece uygulama içinde anlam taşıyan durumlarda düşünebiliriz.
Örneğin:
enum ModalState
{
case Open;
case Closed;
}
Ama açık konuşmak gerekirse Laravel projelerinde benim elim çoğu zaman backed enum’a gidiyor. Çünkü genelde bu değerler bir yerden geliyor, bir yere yazılıyor veya API ile dış dünyaya açılıyor.
Kötü kullanım örneği
Şöyle bir kod düşünelim:
if ($user->role === 'admin') {
//
}
if ($user->role === 'editor') {
//
}
if ($user->role === 'user') {
//
}
Bu kod çalışır. Ama uzun vadede çok güven vermiyor.
Daha sonra biri yanlışlıkla şöyle yazabilir:
if ($user->role === 'admn') {
//
}
PHP buna kızmaz. Çünkü sonuçta bu da bir string.
Ama enum kullandığımızda:
if ($user->role === UserRole::Admin) {
//
}
IDE bizi destekler. Refactor kolaylaşır. Yanlış değer kullanma ihtimali azalır. Kodun niyeti daha açık hale gelir.
Bence enum’un asıl değeri de burada:
Sadece daha “modern” göründüğü için değil, kodun anlamını netleştirdiği için kullanılır.
Kısa özet
Backed enum, arkasında gerçek bir string veya int değer taşıyan enum türüdür.
Pure enum:
enum UserRole
{
case Admin;
}
Backed enum:
enum UserRole: string
{
case Admin = 'admin';
}
Laravel projelerinde backed enum özellikle veritabanı, request, validation ve API response gibi alanlarda çok kullanışlıdır.
Benim genel yaklaşımım şu:
- Veritabanına yazılacaksa backed enum
- Request’ten gelecekse backed enum
- API’de dönecekse backed enum
- Sadece uygulama içi sembolik bir durumsa pure enum düşünülebilir
Enum kullanmak küçük projede bile kodu daha okunabilir yapar. Büyük projede ise magic string karmaşasını azaltır, refactor sürecini kolaylaştırır ve domain’i daha anlaşılır hale getirir.
Kısacası, Laravel’de role, status, type gibi alanlarda hâlâ düz string’lerle ilerliyorsak, backed enum’a geçmek çoğu zaman daha temiz bir adımdır.
Top comments (0)