---
title: 'Denetim Akışı'
source: 'https://academia.sh/tr/kurslar/php-temelleri/denetim-akisi'
course: 'PHP Temelleri'
language: tr
updated: '2026-10-21T05:03:33+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Karşılıksız kalan bir switch ile match dalının sonucunu ölçerek ayırt eder'
    - "switch'in gevşek, match'in katı karşılaştırma yaptığını aynı girdilerle gösterir"
    - 'İç içe döngülerde break ve continue düzeylerinin sonucu nasıl değiştirdiğini doğrular'
    - 'foreach ile referans kullanımının dizide bıraktığı kalıntıyı ölçer ve nasıl temizlendiğini gösterir'
---

# Denetim Akışı

PHP'de karşılıksız kalan dalların davranışı: switch ile match arasındaki fark, gevşek ve katı karşılaştırma, döngü değişkenlerinin ömrü, foreach ve referans tuzağı ve match içinde default kolunun durdurmayı sessize çevirmesi.

İşleçler dersi, tipleri buluşturan işleçlerin neyi bildirdiğini ve neyi susturduğunu ölçtü. Bu ders aynı soruyu dallara soruyor: bir koşulun, bir durumun ya da bir `match` kolunun hiçbiri eşleşmediğinde, yani karşılıksız bir dal kaldığında, dil ne yapıyor? Cevap iki deyimde farklıdır ve bu dersin ölçü sınıfı durdurur: en az bir deyim, eşleşme yoksa yürütmeyi keser.

PHP'de koşullu dallanma için `if`, `elseif` ve `else`, çoklu seçim için `switch` ve `match`, tekrar için `for`, `while`, `do while` ve `foreach` vardır. Programlama Temelleri kursunda (M01/K02) bu yapıların mantığı kurulmuştu; burada yalnız PHP'nin eşleşme ve çıkış davranışı ölçülüyor. Her dosya bir hata işleyicisi kurar ve işleyici, sinyal gelirse onu görünür kılar.

## Karşılıksız Dal: switch ve match

`switch` bir değeri sırayla `case` etiketleriyle karşılaştırır ve hiçbiri eşleşmezse, `default` yoksa, hiçbir şey yapmadan geçer. `match` aynı işi bir ifade olarak yapar ve bir değer döndürür; hiçbir kol eşleşmezse bir `UnhandledMatchError` fırlatır. Aşağıdaki dosya üç değeri iki deyimden geçirir. `$sonuc` değişkeni her turda önceki bir değerle başlar; karşılıksız dalda bu değerin ne olduğu ölçülür.

```php
<?php
// karsiliksiz.php — switch sessizce gecer, match durdurur
$bildirim = 0;
set_error_handler(function (int $seviye) use (&$bildirim): bool {
    $bildirim++;
    return true;
});

foreach ([1, 2, 3] as $kod) {
    $sonuc = 'onceki';
    switch ($kod) {
        case 1:
            $sonuc = 'bir';
            break;
        case 2:
            $sonuc = 'iki';
            break;
    }
    echo "switch($kod): $sonuc\n";

    $sonuc = 'onceki';
    try {
        $sonuc = match ($kod) {
            1 => 'bir',
            2 => 'iki',
        };
        echo "match($kod):  $sonuc\n";
    } catch (UnhandledMatchError $hata) {
        echo "match($kod):  ", get_class($hata), ' (sonuc: ', $sonuc, ")\n";
    }
}
echo 'bildirim: ', $bildirim, "\n";
```

```
switch(1): bir
match(1):  bir
switch(2): iki
match(2):  iki
switch(3): onceki
match(3):  UnhandledMatchError (sonuc: onceki)
bildirim: 0
```

**KN34.** Üçüncü turda `switch` hiçbir şey yapmadı: değişken önceki değerinde kaldı ve bildirim sayacı artmadı. `match` aynı girdide `UnhandledMatchError` fırlattı ve atama gerçekleşmediği için `$sonuc` yine önceki değerinde kaldı; fark, dilin bu durumda artık sessiz kalmamasıdır. `match` ifadesi, eşleşmeyen bir değeri bir hata olarak tanımlar; `switch` ise bunu normal bir yürütme yolu sayar.

## Gevşek ve Katı Karşılaştırma

İkisi arasındaki ikinci fark, karşılaştırmanın sıkılığıdır. `switch` etiketleri `==` ile, yani gevşek eşitlikle karşılaştırır; `match` kolları `===` ile, yani katı eşitlikle. Aynı girdi iki deyimde farklı kola gidebilir. Aşağıdaki dosya beş girdiyi iki deyime verir; etiket ve kol listeleri aynıdır.

```php
<?php
// karsilastirma.php — switch gevsek, match kati karsilastirir
$girdiler = [
    ["'1'", '1'],
    ['null', null],
    ["''", ''],
    ['0', 0],
    ["'a'", 'a'],
];
printf("%-6s%-13s%s\n", 'girdi', 'switch', 'match');
foreach ($girdiler as [$ad, $girdi]) {
    switch ($girdi) {
        case 1:
            $s = 'case 1';
            break;
        case false:
            $s = 'case false';
            break;
        case 'a':
            $s = "case 'a'";
            break;
        default:
            $s = 'default';
    }
    $m = match ($girdi) {
        1 => 'kol 1',
        false => 'kol false',
        'a' => "kol 'a'",
        default => 'default',
    };
    printf("%-6s%-13s%s\n", $ad, $s, $m);
}
```

```
girdi switch       match
'1'   case 1       default
null  case false   default
''    case false   default
0     case false   default
'a'   case 'a'     kol 'a'
```

**KN35.** `'1'` dizgisi `switch`'te `case 1`'e gitti, `match`'te ise `1 =>` koluna uymayıp `default`'a düştü. `null`, boş dizgi ve `0` `switch`'te `case false`'e gitti, çünkü gevşek eşitlikte `false`'la eşittirler; `match`'te hiçbiri `false =>` koluna uymadı. Yalnız `'a'` iki deyimde aynı yere gitti. Bu, İşleçler dersindeki eşitlik tablosunun denetim akışındaki yansımasıdır: `switch` bildirim üretmeden gevşek eşitliğin bütün sürprizlerini devralır.

## İç İçe Döngülerde Çıkış

`break` bir döngüyü bitirir, `continue` bir sonraki tura geçer ve ikisi de bir sayı alabilir: `break 2` iki iç içe döngüden birden çıkar, `continue 2` dıştaki döngünün sonraki turuna geçer. Dil bu sayıyı geçerli bir düzey sınırı dışında kabul etmez, ama sayının neyi atlattığı programcının okuması gereken bir ayrıntıdır. Aşağıdaki dosya üç iç içe durumu çalıştırır ve döngü değişkenlerinin döngü bittikten sonraki değerini de basar.

```php
<?php
// cikis.php — break 2 ve continue 2 dis donguyu etkiler
$satirlar = [];
for ($i = 1; $i <= 3; $i++) {
    for ($j = 1; $j <= 3; $j++) {
        if ($j === 2) {
            continue;
        }
        if ($i === 2) {
            continue 2;
        }
        if ($i === 3 && $j === 3) {
            break 2;
        }
        $satirlar[] = $i . $j;
    }
}
echo implode(',', $satirlar), "\n";
echo "i: $i j: $j\n";
```

```
11,13,31
i: 3 j: 3
```

**KN36.** Çıktıdaki üç çift, her çıkışın etkisini gösterir: `j` ikiye eşit olduğunda iç tur atlandı, `i` ikiye eşit olduğunda dış turun geri kalanı atlandı, `i` üç ve `j` üç olduğunda iki döngü birden bitti. Son satır, PHP'de bir döngü değişkeninin döngü bittikten sonra da yaşadığını gösterir: `i` ve `j` hâlâ tanımlıdır ve çıkış anındaki değerlerini korur. Döngü değişkeninin kapsamı döngü değil, onu içeren fonksiyondur; bu, aynı adı sonradan kullanan koda kalıntı bırakabilir.

## foreach ve Referans Tuzağı

`foreach` bir dizinin elemanlarını sırayla bir değişkene kopyalar; kopya değiştirilirse dizi etkilenmez. Değişken `&` ile bir referans olarak bağlanırsa dizi değişir ve döngü bittikten sonra bu referans yaşamaya devam eder. Referansı temizlemeden aynı adı yeniden kullanan ikinci bir `foreach`, dizinin son elemanının üzerine yazar. Aşağıdaki dosya üç durumu ölçer.

```php
<?php
// referans.php — foreach referansi donguden sonra da yasar
$a = [1, 2, 3];
foreach ($a as $v) {
    $v *= 10;
}
echo 'kopya:         ', implode(',', $a), "\n";

$b = [1, 2, 3];
foreach ($b as &$w) {
    $w *= 10;
}
foreach ($b as $w) {
}
echo 'referans:      ', implode(',', $b), "\n";

$c = [1, 2, 3];
foreach ($c as &$x) {
    $x *= 10;
}
unset($x);
foreach ($c as $x) {
}
echo 'unset ile:     ', implode(',', $c), "\n";
```

```
kopya:         1,2,3
referans:      10,20,20
unset ile:     10,20,30
```

**KN37.** Kopya ile dönen `foreach` diziyi değiştirmedi. Referansla dönen, her elemanı on katına çıkardı. Ardından aynı adı bir kopya olarak kullanan ikinci döngü, referans hâlâ son elemana bağlı olduğu için dizinin son elemanını sessizce ezdi ve `10,20,20` çıktı. `unset($x)` referansı koparttı ve `10,20,30` kaldı. Bu davranış sessizdir: bildirim yok, istisna yok, yalnız yanlış bir dizi.

## Koşulun İçinde Atama

Tek bir karakter farkı, bir koşulu bir atamaya çevirir: `=` ile `==`. PHP bunu sözdizim hatası saymaz, çünkü atama bir ifadedir ve değeri atanan değerdir. Koşul o değere göre karar verir. Aşağıdaki dosya aynı koşulu üç biçimde yazar; hata işleyicisi bir sayaç tutar.

```php
<?php
// kosul_atama.php — if icinde = atama yapar ve degeri kosul sayilir
$bildirim = 0;
set_error_handler(function (int $seviye) use (&$bildirim): bool {
    $bildirim++;
    return true;
});

$durum = 'bos';
if ($durum = 'dolu') {
    echo "atama: dal dogru, durum: $durum\n";
}

$durum = 'bos';
if ($durum == 'dolu') {
    echo "karsilastirma: dal dogru\n";
} else {
    echo "karsilastirma: dal yanlis, durum: $durum\n";
}

$deger = 5;
if ($deger = 0) {
    echo "sifir atama: dal dogru\n";
} else {
    echo "sifir atama: dal yanlis, deger: $deger\n";
}
echo 'bildirim: ', $bildirim, "\n";
```

```
atama: dal dogru, durum: dolu
karsilastirma: dal yanlis, durum: bos
sifir atama: dal yanlis, deger: 0
bildirim: 0
```

**KN38.** `'dolu'` atandığında koşul doğru çıktı ve `$durum` değişti; karşılaştırma ise değeri korudu. `0` atanınca koşul yanlış çıktı ve `$deger` beşten sıfıra düştü. Üç durumda da sayaç sıfır kaldı: dil atamayı koşul içinde meşru sayar ve bir sinyal vermez. Hata, yalnız değişkenin değerinin koşuldan sonra değişmiş olmasından anlaşılır.

## Döngü Kaç Kez Döner

Bir döngünün kaç tur attığı koşuldan çıkarılabilir, ama üç durumda beklenti ile gerçek ayrışır. `do while` koşulu turdan sonra sınar, bu yüzden yanlış bir koşulda bile bir kez döner. Kayan noktalı bir sayaç, `0.1` adımlarla `1`'e ulaştığında beklenenden bir tur fazla atabilir. Döngü sırasında diziye eleman eklemek, `foreach`'in dönüş sayısını değiştirmez, çünkü `foreach` başlangıç anındaki diziyi dolaşır. Aşağıdaki dosya üçünü sayar.

```php
<?php
// tur_sayisi.php — do while bir kez doner, kayan nokta sayaci fazla doner
$say = 0;
do {
    $say++;
} while (false);
echo "do while:    $say\n";

$say = 0;
for ($x = 0; $x < 1; $x += 0.1) {
    $say++;
}
echo "for 0.1 adim: $say\n";

$dizi = [1, 2];
$say = 0;
foreach ($dizi as $eleman) {
    $dizi[] = $eleman * 10;
    $say++;
}
echo "foreach:      $say tur, dizi: ", count($dizi), " eleman\n";
```

```
do while:    1
for 0.1 adim: 11
foreach:      2 tur, dizi: 4 eleman
```

**KN39.** `do while` yanlış koşulda bile bir tur attı. Kayan noktalı sayaç on değil on bir tur attı, çünkü onuncu toplamda sayaç tam `1` olmadı, `1`'in hemen altında kaldı; bu, Değişkenler dersindeki `0.1 + 0.2` ölçümünün döngü tarafıdır. `foreach` iki tur attı ve dizi dört elemana çıktı: dönülen dizi ilk andaki kopyadır. Üçü de sessizdir.

## foreach ve Dizi Olmayan Değer

`foreach` bir dizi ya da bir nesne bekler. Başka bir değer verilirse döngü hiç dönmez ve dil bir `E_WARNING` bildirir; yani bu durum, bu dersin ölçü sınıfından farklı olarak, durdurmaz ama sessiz de değildir. Aşağıdaki dosya `null`, bir dizgi ve boş bir diziyi aynı döngüye verir.

```php
<?php
// dizi_degil.php — foreach dizi olmayan degerde uyarir ve donmez
set_error_handler(function (int $seviye): bool {
    echo $seviye === E_WARNING ? "  [E_WARNING]\n" : "  [baska]\n";
    return true;
});

$girdiler = [
    'null'      => null,
    "'abc'"     => 'abc',
    '[]'        => [],
    '[1, 2]'    => [1, 2],
];
foreach ($girdiler as $ad => $girdi) {
    $say = 0;
    foreach ($girdi as $eleman) {
        $say++;
    }
    echo "$ad: $say tur\n";
}
```

```
  [E_WARNING]
null: 0 tur
  [E_WARNING]
'abc': 0 tur
[]: 0 tur
[1, 2]: 2 tur
```

**KN40.** `null` ve dizgi döngüye girmedi ve her biri bir `E_WARNING` bildirdi; boş dizi ve iki elemanlı dizi bildirimsiz döndü. Boş dizi ile `null` arasındaki bu fark, bir fonksiyonun "sonuç yok" için hangisini döndürdüğünü bir sözleşme hâline getirir: `null` döndürüp `foreach`'e vermek her çağrıda bir uyarı üretir.

## Döngü Sırasında Değişen Dizi

`foreach` değerle çalışırken diziyi başlangıçtaki hâliyle dolaşır; döngü içinde dizi büyütülse bile tur sayısı değişmez. `for` ise koşulu her turda yeniden hesaplar; koşul `count()` ise dizi büyüdükçe tur da uzar. Aşağıdaki dosya aynı büyütmeyi iki döngüde sayar.

```php
<?php
// buyume.php — foreach baslangic dizisini dolasir, for kosulu her turda yeniden hesaplar
$a = [1, 2, 3];
$tur_a = 0;
foreach ($a as $v) {
    if ($tur_a < 5) {
        $a[] = $v;
    }
    $tur_a++;
}
echo 'foreach: ', $tur_a, ' tur, ', count($a), " eleman\n";

$b = [1, 2, 3];
$tur_b = 0;
for ($i = 0; $i < count($b); $i++) {
    if ($tur_b < 3) {
        $b[] = 9;
    }
    $tur_b++;
}
echo 'for:     ', $tur_b, ' tur, ', count($b), " eleman\n";
```

```
foreach: 3 tur, 6 eleman
for:     6 tur, 6 eleman
```

**KN41.** `foreach` üç tur döndü ve dizi altı elemana çıktı: dolaşılan, başlangıçtaki üç elemanlı kopyaydı. `for` altı tur döndü, çünkü `count($b)` her turda yeni uzunluğu verdi. Biri büyümeyi görmez, öbürü görür; ikisi de bildirim üretmez. Döngünün döndüğü dizi döngü içinde değişiyorsa tur sayısı, hangi döngü yapısının seçildiğine bağlıdır.

## Sınırlayıcı Ölçüm

`match` karşılıksız girdide durdurduğu için, bir kolun `default` taşıması durdurmayı sessize çevirir. Bu ders sınıfının sınırı budur: aynı deyim, tek bir kol eklenince durdurur sınıfından sessiz sınıfa geçer. Aşağıdaki dosya, `default` kolu olan ve olmayan iki fonksiyonu aynı girdilerle çalıştırır. Sonuç önce hesaplanır, sonra yazdırılır.

```php
<?php
// varsayilan.php — default kolu match'in durdurmasini sessize cevirir
function ad_katisi(int $kod): string
{
    return match ($kod) {
        1 => 'bir',
        2 => 'iki',
    };
}

function ad_varsayilan(int $kod): string
{
    return match ($kod) {
        1 => 'bir',
        2 => 'iki',
        default => 'bilinmiyor',
    };
}

foreach ([1, 7] as $kod) {
    try {
        $katisi = ad_katisi($kod);
    } catch (UnhandledMatchError $hata) {
        $katisi = get_class($hata);
    }
    $varsayilan = ad_varsayilan($kod);
    printf("%d  katisi: %-20s varsayilan: %s\n", $kod, $katisi, $varsayilan);
}
```

```
1  katisi: bir                  varsayilan: bir
7  katisi: UnhandledMatchError  varsayilan: bilinmiyor
```

**KN42.** `1` girdisinde iki fonksiyon de `'bir'` döndürdü. `7` girdisinde `default` kolu olmayan fonksiyon `UnhandledMatchError` fırlattı, olan fonksiyon ise `'bilinmiyor'` döndürdü ve hiçbir şey bildirmedi. Bu durumda `default` iki şeyi birden yapar: eşleşmeyen girdiyi sessizce kabul eder ve girdinin eşleşmediğini programdan saklar. Hangi seçimin doğru olduğu, eşleşmeyen girdinin beklenen mi yoksa bir hata mı olduğuna bağlıdır; ölçüm yalnız seçimin sonucunu gösterir.

## Özet

- Denetim akışının ölçü sınıfı durdurur: `match` karşılıksız kolda `UnhandledMatchError` fırlatır, `switch` ise sessizce geçer ve değişkeni önceki değerinde bırakır.
- `switch` etiketleri gevşek, `match` kolları katı eşitlikle karşılaştırır: `'1'` `switch`'te `case 1`'e gider, `match`'te `default`'a düşer.
- `break 2` ve `continue 2` iç içe döngülerde dış döngüyü etkiler; döngü değişkenleri döngüden sonra da tanımlı kalır.
- Referansla çalışan bir `foreach` döngüden sonra referansı bırakır; `unset` olmadan aynı adla ikinci bir döngü dizinin son elemanını ezer.
- `match`'e bir `default` kolu eklemek durdurmayı sessize çevirir ve eşleşmeyen girdiyi gizler.

## Sonraki Adım

Karşılıksız bir dalın ne yaptığı görüldü: `switch` geçer, `match` durdurur. Fonksiyonlar dersi aynı soruyu çağrılara soruyor: bir fonksiyona beklenenden fazla argüman verildiğinde, fazlalık nereye gidiyor?
