
PHP'de Statik Üyeler, Sabitler ve Enum Kullanımı
Uygulamalarda durum bilgisi çoğunlukla metin olarak taşınır: bir siparişin durumu bekliyor, hazırlanıyor ya da tamamlandı olabilir. Bu değerler metin olarak yazıldığında yazım hataları çalışma zamanına kadar fark edilmez, geçerli değerlerin listesi hiçbir yerde tanımlı olmaz ve karşılaştırmalar kod tabanına dağılır.
Bu bölümde sabitler, statik üyeler ve enum yapısı ele alınıyor. Üçü de sınıf örneği olmadan erişilen yapılardır, ancak kullanım alanları belirgin biçimde ayrışır.
Sabitler
Sabitler çalışma boyunca değişmeyen değerleri taşır. Sınıf içinde tanımlanan sabitler, ilgili oldukları kavramın yanında durdukları için genel ad alanına yayılan tanımlardan daha düzenlidir.
final class Yukleme
{
public const int AZAMI_BOYUT = 5 * 1024 * 1024; // tip bildirimi PHP 8.3 ile
public const array IZINLI_TURLER = ['image/jpeg', 'image/png', 'image/webp'];
public function denetle(int $boyut, string $tur): void
{
if ($boyut > self::AZAMI_BOYUT) {
throw new DomainException('Dosya çok büyük');
}
if (!in_array($tur, self::IZINLI_TURLER, strict: true)) {
throw new DomainException('Desteklenmeyen tür');
}
}
}Sabitler arayüzlerde de tanımlanabilir ve uygulayan tüm sınıflardan erişilir. Alt sınıfın sabiti yeniden tanımlamasını engellemek gerekiyorsa final kullanılır.
Ad alanı düzeyindeki sabitler için iki yol vardır. define çalışma zamanında, const ise derleme aşamasında tanımlar; ikincisi daha hızlıdır ve ad alanına saygı gösterir. Yapılandırma değerleri sabit olarak değil, okunabilir bir yapılandırma nesnesi üzerinden taşınmalıdır; sabitler ortama göre değişemez.
Statik özellik ve metotlar
Statik üyeler sınıfa aittir, nesneye değil. Nesne durumuna ihtiyaç duymayan yardımcı işlemler için uygundur. Ancak statik özelliklerde tutulan veri, isteğin tamamı boyunca paylaşılan gizli bir durum oluşturur ve test yazmayı zorlaştırır.
final class Slug
{
private const array HARFLER = ['ı' => 'i', 'ğ' => 'g', 'ü' => 'u',
'ş' => 's', 'ö' => 'o', 'ç' => 'c'];
public static function uret(string $baslik): string
{
$metin = strtr(mb_strtolower($baslik, 'UTF-8'), self::HARFLER);
return trim(preg_replace('/[^a-z0-9]+/u', '-', $metin), '-');
}
}
echo Slug::uret('Kaz Dağları Yürüyüş Notları'); // kaz-daglari-yuruyus-notlariStatik çağrılar yer değiştirilemez. Bir sınıf içeride başka bir sınıfın statik metodunu çağırıyorsa, o bağımlılık testte değiştirilemez ve yapıcı metoda bakılarak görülemez. Bu yüzden veritabanı erişimi, dosya işlemleri ve dış servis çağrıları statik metotlara konulmaz.
Tek örnek deseni de aynı sorunu taşır. Genel erişim noktası sağlaması pratik görünse de, bağımlılığı gizlediği ve durumu istekler arasında paylaştırdığı için bugün önerilmez. Aynı ihtiyaç, nesnenin tek örneğini üreten bir kapsayıcı ile bağımlılık aktarımı üzerinden karşılanır.
Enum
Enum, sınırlı sayıda değerden oluşan bir tip tanımlar. Değerler tip sistemi tarafından denetlendiği için yazım hatası çalışma zamanına kalmaz ve geçerli değerlerin listesi tek bir yerde durur.
enum SiparisDurumu: string
{
case Bekliyor = 'bekliyor';
case Hazirlaniyor = 'hazirlaniyor';
case Kargoda = 'kargoda';
case Tamamlandi = 'tamamlandi';
public function etiket(): string
{
return match ($this) {
self::Bekliyor => 'Ödeme bekleniyor',
self::Hazirlaniyor => 'Hazırlanıyor',
self::Kargoda => 'Kargoya verildi',
self::Tamamlandi => 'Teslim edildi',
};
}
public function iptalEdilebilir(): bool
{
return in_array($this, [self::Bekliyor, self::Hazirlaniyor], strict: true);
}
}Değer taşıyan enum, veritabanı ile arasındaki dönüşümü kolaylaştırır. from geçersiz değerde istisna fırlatır, tryFrom ise null döndürür. Dış kaynaktan gelen veride ikincisi tercih edilir.
$durum = SiparisDurumu::from($satir['durum']); // geçersizse ValueError
$durum = SiparisDurumu::tryFrom($istek['durum'] ?? ''); // geçersizse null
foreach (SiparisDurumu::cases() as $secenek) { // tüm değerler
printf('<option value="%s">%s</option>', $secenek->value, $secenek->etiket());
}
// veritabanına yazarken
$sorgu->execute(['durum' => $durum->value]);Enum arayüz uygulayabilir ve sabit tanımlayabilir. Böylece farklı enum tipleri ortak bir sözleşmeye bağlanır. Enum içinde özellik tanımlanamaz; durum taşıması gereken bir kavram enum ile değil sınıfla ifade edilir.
interface Etiketli
{
public function etiket(): string;
}
enum Oncelik: int implements Etiketli
{
case Dusuk = 1;
case Orta = 2;
case Yuksek = 3;
public function etiket(): string
{
return match ($this) {
self::Dusuk => 'Düşük',
self::Orta => 'Orta',
self::Yuksek => 'Yüksek',
};
}
}Durum geçişlerini enum içinde tanımlamak
Durumların hangi sırayla değişebileceği çoğu uygulamada dağınık koşullarla ifade edilir. Bu kural enumun kendisine taşındığında, geçerli geçişlerin listesi tek bir yerde durur ve geçersiz bir geçiş denemesi anında hata verir.
enum SiparisDurumu: string
{
case Bekliyor = 'bekliyor';
case Hazirlaniyor = 'hazirlaniyor';
case Kargoda = 'kargoda';
case Tamamlandi = 'tamamlandi';
case Iptal = 'iptal';
/** @return list<self> */
public function sonraki(): array
{
return match ($this) {
self::Bekliyor => [self::Hazirlaniyor, self::Iptal],
self::Hazirlaniyor => [self::Kargoda, self::Iptal],
self::Kargoda => [self::Tamamlandi],
self::Tamamlandi, self::Iptal => [],
};
}
public function gecebilirMi(self $hedef): bool
{
return in_array($hedef, $this->sonraki(), strict: true);
}
}
if (!$siparis->durum->gecebilirMi(SiparisDurumu::Kargoda)) {
throw new DomainException('Bu durumdan kargoya geçilemez');
}Aynı yapı arayüzde de kullanılır: kullanıcıya yalnızca geçerli sonraki adımlar gösterilir. Kural tek yerde tanımlı olduğu için arayüz ile iş kuralı arasında ayrışma oluşmaz.
Enum ile metin sabiti karşılaştırması
Aynı işin metin sabitleriyle yapıldığı bir kodda geçersiz değerin fark edilmesi, o değerin bir karşılaştırmaya girmesine kadar gecikir. Enum kullanıldığında hata, değerin üretildiği noktada ortaya çıkar.
// metin ile: yazım hatası sessizce yanlış davranışa yol açar
if ($siparis->durum === 'hazirlniyor') { // hiçbir zaman doğru olmaz
// ...
}
// enum ile: yanlış yazım anında hata verir
if ($siparis->durum === SiparisDurumu::Hazirlaniyor) {
// ...
}match ifadesi enum ile birlikte kullanıldığında ek bir kazanç sağlar: karşılanmayan bir durum kaldığında çalışma zamanında hata alınır. Enuma yeni bir değer eklendiğinde, o değeri işlemeyen tüm yerler ilk denemede kendini gösterir.
Enumun sınırları
Enum örnekleri tekildir: aynı durum her yerde aynı nesnedir. Bu yüzden karşılaştırma === ile yapılabilir ve nesne kimliği güvenle kullanılır. Ancak aynı nedenle enum durum taşıyamaz; her siparişe özel bir değer tutulacaksa bu bilgi enumda değil sınıfta yer alır.
Değer taşıyan enumlar JSON çıktısında kendi değerlerine dönüşür. Değer taşımayan enumlar ise doğrudan serileştirilemez; API yanıtında kullanılacak her enumun bir değeri olması bu yüzden pratik bir kuraldır.
enum Durum: string { case Aktif = 'aktif'; }
enum Renk { case Kirmizi; }
echo json_encode(['durum' => Durum::Aktif]); // {"durum":"aktif"}
echo json_encode(['renk' => Renk::Kirmizi]); // false döner, çıktı üretilmezVeritabanı tarafında değerin metin olarak saklanması, sayısal karşılıklardan daha dayanıklıdır. Sayı kullanıldığında kayıtların anlamı şemaya bakılarak anlaşılamaz ve sıralamaya bağlı hatalar oluşabilir.
Kontrol listesi
- Sınırlı değer kümeleri metin yerine enum ile tanımlanıyor.
- Dış kaynaktan gelen değerlerde
tryFromkullanılıp sonuç denetleniyor. - Sabitler ilgili oldukları sınıfın içinde ve tip bildirimiyle tanımlı.
- Statik metotlar dış dünyaya erişmiyor; yalnızca saf hesaplama yapıyor.
- Tek örnek deseni yerine bağımlılık aktarımı kullanılıyor.
- Enum üzerinde yapılan
matchifadelerinde tüm durumlar karşılanıyor.
İlgili yazılar
PHP eğitim serisi
Bu yazı, temel sözdiziminden üretim ortamına kadar ilerleyen 25 bölümlük serinin bir parçası. Bölümler sırayla okunacak biçimde hazırlandı, ancak her biri tek başına da kullanılabilir.
Temeller
- Kurulum ve temel sözdizimi
- Döngüler ve akış kontrolü
- Diziler
- Fonksiyonlar
- String fonksiyonları
- Süper globaller
- Form işleme
- Dosya işlemleri
Dilin ayrıntıları
Nesne yönelimli PHP
- Sınıf ve nesne
- Kalıtım, arayüz ve trait
- Statik üyeler, sabitler ve enum (bu yazı)
- Namespace, Composer ve autoload
Veri ve güvenlik
- PDO ile veritabanı işlemleri
- Oturum yönetimi ve kimlik doğrulama
- Güvenli çıktı ve XSS
- JSON ile veri değişimi
Dış dünya ve üretim
Yorumlar
İlk yorumu sen yap.
İlgili Yazılar

PHP Uygulamasını Üretime Almak: Yapılandırma ve Güvenlik
Geliştirme makinesinde çalışan kod ile üretimde güvenle çalışan kod arasındaki fark yapılandırmadır. Ayarlar, izinler, dağıtım akışı ve son kontroller.

PHP ile REST API Yazmak: Yönlendirme ve HTTP Durum Kodları
Bir API'nin kalitesi çoğunlukla ayrıntılarda belli olur: doğru durum kodu, tutarlı hata biçimi ve öngörülebilir adresler. Saf PHP ile uçtan uca kurulum.

PHPUnit ile Birim Test Yazmak: Kurulum, Sahte Nesneler ve Kapsam
Testin amacı hata bulmak değil, değişikliği güvenle yapabilmektir. Kurulum, ilk test, sahte nesneler ve test edilebilir kodun özellikleri.