PHP'de koşullu kod çalıştırmanın üç yolu vardır: if/elseif/else herhangi bir koşulu sınar; switch tek bir değeri birçok seçenekle gevşek (==) karşılaştırma kullanarak eşleştirir; PHP 8.0 ile gelen match ise katı (===) karşılaştırma yapan, değer döndüren ve hiçbir dal eşleşmezse UnhandledMatchError fırlatan bir ifadedir. Yeni kodda tek bir değere göre sonuç üretiyorsanız çoğu zaman match, birden fazla deyim çalıştırmanız gerekiyorsa if en okunaklı seçimdir.
Bu yazıda üç yapının sözdizimini, şablonlarda kullanılan alternatif yazımı, switch içindeki düşme (fall-through) davranışını, switch ile match arasındaki farkları ve PHP 8.5'te kullanımdan kaldırılan bir case yazımını çalıştırılmış örneklerle anlatıyoruz. Serinin diğer yazıları PHP öğrenme rehberi sayfasında.
if, elseif ve else

if (ifade) deyim yapısı, parantez içindeki ifadeyi mantıksal değere çevirir; sonuç true ise deyimi çalıştırır, false ise atlar. Birden fazla deyim çalıştırmak için süslü parantezle bir blok oluşturulur. else, koşul sağlanmadığında çalışacak alternatifi; elseif ise önceki koşullar yanlış çıktığında denenecek yeni bir koşulu tanımlar. Birden fazla elseif olabilir ve yalnızca doğru çıkan ilkinin bloğu çalışır.
<?php
function harfNotu(int $puan): string
{
if ($puan >= 85) {
return 'AA';
} elseif ($puan >= 70) {
return 'BA';
} elseif ($puan >= 50) {
return 'CC';
} else {
return 'FF';
}
}
echo harfNotu(92), "\n"; // çıktı: AA
echo harfNotu(70), "\n"; // çıktı: BA
echo harfNotu(41), "\n"; // çıktı: FF
Koşul ifadesinin mantıksal değere nasıl çevrildiği, yani hangi değerlerin yanlış sayıldığı önemlidir: 0, boş metin, "0", boş dizi ve null yanlıştır. Tam liste veri tipleri yazısında. elseif tek kelime veya else if iki kelime olarak yazılabilir; süslü parantezli yazımda ikisi aynı davranır.
Sarkan else sorunu
Süslü parantez kullanmadan iç içe if yazdığınızda else her zaman kendisine en yakın if'e bağlanır; girinti PHP için hiçbir anlam taşımaz. Aşağıdaki örnekte else dıştaki if'e aitmiş gibi görünse de içteki if ($indirimVar)'a bağlıdır. Dış koşul yanlış olduğu için iç blok hiç değerlendirilmez ve "Önce üye olun" mesajı yazılmaz.
<?php
$uyeMi = false;
$indirimVar = true;
if ($uyeMi)
if ($indirimVar)
echo "Üye indirimi\n";
else
echo "Önce üye olun\n"; // bu else içteki if'e aittir
echo "bitti\n"; // çıktı: bitti
Koşulda = ile == karıştırmak
Atama da bir ifade olduğu için if ($x = 5) yazımı hata vermez: önce $x'e 5 atanır, sonra atanan değer (5) doğru sayılır ve blok her seferinde çalışır. Karşılaştırma için == veya tercihen === kullanın.
<?php
$x = 3;
if ($x = 5) {
echo "Koşul her zaman doğru, x artık $x\n";
}
if ($x === 5) {
echo "Doğru karşılaştırma\n";
}
Koşul her zaman doğru, x artık 5
Doğru karşılaştırmaKoşulda atama her zaman hata değildir; bir fonksiyonun sonucunu hem saklayıp hem kontrol etmek için bilinçli olarak da kullanılır. Kılavuzun öncelik notuna göre if (!$a = foo()) yazımı, atamanın sol tarafı değişken olmak zorunda olduğu için !($a = foo()) olarak gruplanır ve foo() sonucu $a'ya konur. Bu yazımı kullanıyorsanız niyetinizi göstermek için atamayı parantez içine alıp açık bir karşılaştırma eklemek okuyana yardımcı olur:
<?php
function kullaniciBul(int $id): ?string
{
return [1 => 'Ayşe', 2 => 'Mehmet'][$id] ?? null;
}
if (!$ad = kullaniciBul(3)) {
echo "Kullanıcı bulunamadı\n"; // çıktı: Kullanıcı bulunamadı
}
if (($ad = kullaniciBul(2)) !== null) {
echo "Hoş geldin, $ad\n"; // çıktı: Hoş geldin, Mehmet
}
İkinci koşuldaki !== null kontrolü ayrıca önemli: fonksiyon geçerli bir sonuç olarak boş metin veya 0 döndürebiliyorsa, yalnızca doğruluk kontrolüne güvenmek bu sonuçları da "bulunamadı" gibi yorumlar.
Şablonlar için alternatif sözdizimi
PHP, if, while, for, foreach, switch ve declare yapıları için süslü parantez yerine iki nokta üst üste ve endif;, endforeach; gibi kapanış kelimeleri kullanan bir yazım sunar. HTML ağırlıklı şablonlarda hangi kapanışın hangi bloğa ait olduğunu görmeyi kolaylaştırır. else: ve elseif: da bu yazımla kullanılabilir; ancak aynı blokta iki yazımı karıştırmak desteklenmez.
<?php $sepet = ['kalem' => 2, 'defter' => 0]; ?>
<?php foreach ($sepet as $urun => $adet): ?>
<?php if ($adet > 0): ?>
<p><?= $urun ?>: <?= $adet ?> adet</p>
<?php else: ?>
<p><?= $urun ?>: stokta yok</p>
<?php endif; ?>
<?php endforeach; ?>
<p>kalem: 2 adet</p>
<p>defter: stokta yok</p>Etiketlerin ve kapanış etiketinden sonraki satır sonunun nasıl işlendiği temel sözdizimi yazısında, döngülerin alternatif yazımı döngüler yazısında anlatılıyor.
switch deyimi

switch, aynı ifadeyi birçok değerle karşılaştırırken art arda yazılmış if/elseif zincirine göre daha düzenli bir yazım sunar. Çalışma biçimini doğru anlamak önemlidir: PHP önce hiçbir kodu çalıştırmaz; değeri eşleşen ilk case bulunduğunda oradan itibaren deyimleri çalıştırmaya başlar ve switch bloğunun sonuna veya ilk break deyimine kadar devam eder. break unutulursa sonraki case blokları da çalışır; buna düşme (fall-through) denir.
<?php
$gun = 'cumartesi';
switch ($gun) {
case 'cumartesi':
case 'pazar':
echo "Hafta sonu\n";
break;
case 'cuma':
echo "Haftanın son iş günü\n";
// break unutuldu: aşağıya düşer
default:
echo "Hafta içi\n";
}
// çıktı: Hafta sonu
$gun = 'cuma';
switch ($gun) {
case 'cuma':
echo "Haftanın son iş günü\n";
default:
echo "Hafta içi\n";
}
/* çıktı:
Haftanın son iş günü
Hafta içi
*/
İlk switch bloğunda düşme bilinçli olarak kullanıldı: boş bırakılan case 'cumartesi': doğrudan bir sonraki case'in deyimlerine geçer ve iki değer aynı sonucu üretir. İkinci blokta ise break unutulduğu için cuma günü hem "son iş günü" hem "hafta içi" mesajı yazıldı. default dalı hiçbir case eşleşmediğinde çalışır; teknik olarak herhangi bir sırada yazılabilir ama gelenek olarak sona konur. Birden fazla default derleme hatasıdır.
switch değerini yalnızca bir kez değerlendirir ve sonucu her case ile karşılaştırır. case değeri bir ifade olabilir, ama bu ifade kendi başına hesaplanıp switch değeriyle gevşek karşılaştırılır. Aralık kontrolü gibi karmaşık koşullar için kılavuz switch (true) kalıbını veya doğrudan if/else kullanmayı önerir.
switch gevşek karşılaştırma yapar
switch ve case değerleri == ile karşılaştırılır. Bu yüzden '1' metni case 1: dalıyla eşleşir. PHP 8.0 ile metin ve sayı karşılaştırma kuralları değişti ve bu değişiklik switch için de geçerlidir: PHP 7'de switch ('a') bloğu case 0: ile eşleşirken PHP 8'de eşleşmez, çünkü sayısal olmayan bir metin artık sayıya çevrilerek değil, sayı metne çevrilerek karşılaştırılır.
<?php
var_dump(0 == 'a'); // PHP 8: bool(false), PHP 7: bool(true)
var_dump('1' == '01'); // çıktı: bool(true)
var_dump(100 == '1e2'); // çıktı: bool(true)
switch ('a') {
case 0:
echo "0\n";
break;
case 'a':
echo "a\n"; // PHP 8 çıktısı: a
break;
}
Bu kuralların tamamı ve karşılaştırma tabloları eşitlik ve tip dönüşümü yazısında anlatılıyor.
PHP 8.5: case sonrasında noktalı virgül kullanımdan kaldırıldı
PHP uzun süre case satırını iki nokta yerine noktalı virgülle bitirmeye izin veriyordu. Kılavuzun değişiklik tablosuna göre bu yazım PHP 8.5'te kullanımdan kaldırıldı ve her satır için bir deprecated bildirimi üretir. Kod hâlâ çalışır, ancak eski projelerde bu bildirimleri görüyorsanız noktalı virgülleri iki noktayla değiştirin.
<?php
$secim = 'b';
switch ($secim) {
case 'a';
echo "A seçildi\n";
break;
case 'b';
echo "B seçildi\n";
break;
}
Deprecated: Case statements followed by a semicolon (;) are deprecated, use a colon (:) instead in /yol/ornek.php on line 4
Deprecated: Case statements followed by a semicolon (;) are deprecated, use a colon (:) instead in /yol/ornek.php on line 7
B seçildimatch ifadesi (PHP 8.0 ve sonrası)
match, switch'e benzer biçimde bir konu ifadesini (subject) birden fazla seçenekle karşılaştırır, ama dört temel farkı vardır. Birincisi, karşılaştırmayı katı eşitlikle (===) yapar; tip de aynı olmalıdır. İkincisi, bir ifade olduğu için değer döndürür ve doğrudan bir değişkene atanabilir veya return ile döndürülebilir. Üçüncüsü, dallar arasında düşme yoktur; her dal tek bir ifade içerir ve break gerekmez. Dördüncüsü, kapsayıcı (exhaustive) olmak zorundadır: hiçbir dal eşleşmezse ve default yoksa UnhandledMatchError fırlatılır.
Bir dalda virgülle ayrılmış birden fazla koşul yazılabilir; bu, aynı sonucu veren ayrı dallar yazmanın kısa yoludur ve mantıksal "veya" anlamı taşır. Dallar yukarıdan aşağıya denenir ve bir dalın koşul ifadesi yalnızca önceki dallar eşleşmediyse değerlendirilir. Yalnızca eşleşen dalın sonuç ifadesi çalıştırılır. match tek başına bir deyim olarak kullanıldığında noktalı virgülle bitirilmelidir.
<?php
function kargoUcreti(float $tutar): string
{
return match (true) {
$tutar >= 500 => 'Ücretsiz',
$tutar >= 200 => '29,90 TL',
$tutar > 0 => '49,90 TL',
default => 'Sepet boş',
};
}
echo kargoUcreti(750), "\n"; // çıktı: Ücretsiz
echo kargoUcreti(250), "\n"; // çıktı: 29,90 TL
echo kargoUcreti(0), "\n"; // çıktı: Sepet boş
$durum = 'kargoda';
$mesaj = match ($durum) {
'hazirlaniyor', 'onaylandi' => 'Siparişiniz hazırlanıyor',
'kargoda' => 'Siparişiniz yolda',
'teslim' => 'Teslim edildi',
};
echo $mesaj, "\n"; // çıktı: Siparişiniz yolda
İlk fonksiyon match (true) kalıbını kullanıyor: konu ifadesi true olduğu için her dalın koşulu bir karşılaştırma olur ve doğru çıkan ilk dal seçilir. Bu kalıp, uzun if/elseif zincirlerinin yerine aralık kontrolü yapmak için kullanılır. Dalların sırası önemlidir; daha geniş koşulu ($tutar > 0) daha dar olanlardan sonra yazmalısınız.
Katı karşılaştırma ve UnhandledMatchError
Aşağıdaki örnek, aynı '1' metninin switch ve match tarafından nasıl farklı eşleştirildiğini gösteriyor. switch metni tamsayı 1 ile eşleştirirken, match tamsayı dalını atlayıp metin dalını seçiyor. Son bölümde ise hiçbir dalı eşleşmeyen bir değer UnhandledMatchError fırlatıyor; hata mesajı eşleşmeyen değeri de içerir.
<?php
$kod = '1';
switch ($kod) {
case 1:
echo "switch: 1 ile eşleşti\n"; // çıktı: switch: 1 ile eşleşti
break;
}
echo match ($kod) {
1 => "match: int 1\n",
'1' => "match: string '1'\n", // çıktı: match: string '1'
};
try {
echo match ((int) $kod + 1) {
1 => 'bir',
};
} catch (\UnhandledMatchError $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
switch: 1 ile eşleşti
match: string '1'
UnhandledMatchError: Unhandled match case 2Bu hatayı try/catch ile yakalayabilirsiniz, ama çoğu durumda doğru çözüm beklenmeyen değerleri bir default dalıyla açıkça ele almaktır. Hata yakalamanın ayrıntıları try, catch ve exception yazısında anlatılıyor. Enum değerleriyle kullanıldığında match özellikle güçlüdür, çünkü enum durumları === ile güvenle karşılaştırılır; örnekler PHP enum yazısında.
Aynı işi üç yolla yazmak
Farkları somutlaştırmak için bir HTTP durum kodunu açıklama metnine çeviren küçük bir görevi üç yapıyla da yazalım. Üçü de aynı sonucu verir, ama kod uzunluğu ve hata yapma olasılığı farklıdır.
<?php
$kod = 404;
// 1) if / elseif / else
if ($kod === 200) {
$metin = 'Tamam';
} elseif ($kod === 404) {
$metin = 'Bulunamadı';
} else {
$metin = 'Bilinmiyor';
}
echo $metin, "\n"; // çıktı: Bulunamadı
// 2) switch
switch ($kod) {
case 200:
$metin = 'Tamam';
break;
case 404:
$metin = 'Bulunamadı';
break;
default:
$metin = 'Bilinmiyor';
}
echo $metin, "\n"; // çıktı: Bulunamadı
// 3) match
echo match ($kod) {
200 => 'Tamam',
404 => 'Bulunamadı',
default => 'Bilinmiyor',
}, "\n"; // çıktı: Bulunamadı
if sürümünde karşılaştırma operatörünü siz seçersiniz; burada === kullanıldı. switch sürümünde her dalın break ile bitmesi gerekir ve karşılaştırma gevşektir: $kod değeri '404' metni olsaydı yine eşleşirdi. match sürümü ise hem en kısa yazım hem de doğrudan bir değer üretir; sonucu ara değişkene atamadan echo ile yazdırabildik. Değer '404' metni olsaydı match tamsayı dalını eşleştirmez ve default dalına düşerdi. Hangi davranışı istediğinize göre seçim yapın: dışarıdan metin olarak gelen verilerde ya önce tipi dönüştürün ya da gevşek karşılaştırmanın sonuçlarını bilerek switch kullanın.
switch ile match karşılaştırması

| Özellik | switch | match |
|---|---|---|
| Karşılaştırma | Gevşek (==) | Katı (===) |
| Değer döndürür mü? | Hayır, deyimdir | Evet, ifadedir |
| Düşme (fall-through) | break yoksa sonraki case çalışır | Yok |
| Dal başına | Birden fazla deyim | Tek ifade |
| Eşleşme yoksa | Hiçbir şey olmaz | UnhandledMatchError |
| Aynı sonuç için birden fazla değer | Boş case satırlarını art arda yazmak | Virgülle ayırmak |
| Kullanılabildiği sürüm | Tüm sürümler | PHP 8.0 ve sonrası |
Pratik bir kural olarak, bir değerden başka bir değer üretiyorsanız match tercih edin; daha kısa ve tip açısından daha güvenlidir. Her dalda birden çok satırlık iş yapıyorsanız veya düşme davranışına bilinçli olarak ihtiyaç duyuyorsanız switch ya da if kullanın.
Sık yapılan hatalar
- switch içinde break unutmak: Sonraki
caseblokları da çalışır. - switch'in gevşek karşılaştırmasını unutmak: Metin ve sayı karışık değerlerde beklenmedik eşleşmeler olabilir; tip önemliyse
matchkullanın. - match'e default eklememek: Beklenmeyen bir değer geldiğinde
UnhandledMatchErrorbetiği durdurur. - Koşulda = yazmak: Atama her zaman doğru sayılan bir değer üretebilir.
- Süslü parantezsiz iç içe if:
elseen yakınif'e bağlanır. - Alternatif yazımda else if kullanmak: İki nokta ile
elseifbitişik yazılmalıdır.
Sık Sorulan Sorular
match ile switch arasındaki en önemli fark nedir?
match katı karşılaştırma (===) yapar ve değer döndürür; switch gevşek karşılaştırma (==) yapar ve yalnızca deyimleri çalıştırır. Ayrıca match'te düşme yoktur ve eşleşme bulunamazsa hata fırlatılır.
match içinde birden fazla satır kod çalıştırabilir miyim?
Her dal tek bir ifade alır. Birden fazla işlem gerekiyorsa bu işlemleri bir fonksiyona taşıyıp dalda o fonksiyonu çağırabilirsiniz; ya da switch veya if kullanabilirsiniz.
elseif mi else if mi yazmalıyım?
Süslü parantezli yazımda ikisi aynı sonucu verir. Alternatif (iki noktalı) yazımda yalnızca bitişik elseif geçerlidir; bu yüzden her yerde elseif kullanmak tutarlı bir seçimdir.
UnhandledMatchError nasıl düzeltilir?
Hata, match ifadesine hiçbir dalın karşılamadığı bir değer geldiğini gösterir. Mesajdaki değeri kontrol edin; geçerli bir değerse yeni bir dal ekleyin, geçersiz değerler için default dalında anlamlı bir sonuç döndürün veya kendi istisnanızı fırlatın.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: PHP öğrenme rehberi · PHP döngüler · PHP eşitlik ve karşılaştırma · PHP enum kullanımı · PHP try catch · PHP operatörler