---
title: Yönlendirme
source: 'https://academia.sh/tr/kurslar/web-uygulama-cercevesi/yonlendirme'
course: 'Web Uygulama Çerçevesi'
language: tr
updated: '2026-10-21T05:03:39+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Rota kalıbındaki parametreyi, grup önekini ve adlandırılmış rotadan URL üretimini bir yönlendirici modelinde okur'
    - 'İlk eşleşen rotanın kazanması nedeniyle geniş bir kalıbın sonradan kaydedilen dar kalıbı gölgelediğini ölçer'
    - 'Kayıt sırası değişince gölgelenen rotanın koştu sınıfına geçtiğini karşılaştırır'
    - 'Gölgeyi doğuran etkenin sıra değil kalıbın genişliği olduğunu desen kısıtıyla ölçer'
---

# Yönlendirme

Rota kalıpları, parametreler, gruplar ve adlandırılmış rotalar; kayıt sırasında ilk eşleşen rotanın kazanması ve bir rotanın başka bir rotanın gölgesinde bağlanmadan kalması.

Önceki ders isteğin hangi eyleme düştüğünü hazır verdi. Bu ders o adımı açar. Çerçeve bir isteği karşılamak için kayıtlı rotalara tek tek bakar ve bu bakışın kuralı yalnızca bir cümleden oluşur. İki kalıp aynı yola uyduğunda neyin olacağı, o cümlenin nasıl yazıldığına bağlıdır.

## Rota Kalıbı ve Parametre

Bir rota (route) dört şeyi bir araya getirir: bir HTTP yöntemi, bir yol kalıbı, bir parça adı ve bir eylem. Kalıp, yolun sabit kısımlarını ve süslü parantezle yazılan **parametreleri** taşır. `/yazilar/{id}` kalıbı `/yazilar/7` yoluna uyar ve eylem `id` parametresini `7` olarak alır. Çerçeve kalıbı bir düzenli ifadeye çevirir: her parametre, eğik çizgi içermeyen bir ya da daha çok karakterle eşleşen bir gruba dönüşür.

Aynı kalıbı birçok rotada yinelememek için rotalar **gruplanır**. Grup ortak bir önek taşır: `/yazilar` grubu içindeki `/{id}` kalıbı gerçekte `/yazilar/{id}` olur. Gerçek çerçevelerde grup ayrıca bir ara katman listesini her üyesine ekleyebilir; ara katmanların kendisi beşinci dersin konusudur, burada yalnızca önek modellenir. Üçüncü araç **adlandırılmış rotadır**: rota bir adla kaydedilir ve URL, kalıptan o adla üretilir. Böylece bir kalıp değişince adresin yazıldığı her yeri aramak gerekmez.

`yonlendirici.php` bu üç aracı ve eşleştirme kuralını tek sınıfta toplar. Bu dosya KAYNAK olarak verilir ve sonraki iki ölçüm onu `require_once` ile yükler.

```php
<?php
// yonlendirici.php — kayıt sırasıyla eşleşen küçük bir yönlendirici
declare(strict_types=1);
require_once 'kostu.php';

final class Yanit {
    public function __construct(public int $durum, public string $govde = '') {}
}

final class Yonlendirici {
    private array $rotalar = [];
    private array $adlar = [];
    private array $onekler = [];
    public function grup(string $onek, Closure $kayit): void {
        $this->onekler[] = $onek;
        $kayit($this);
        array_pop($this->onekler);
    }
    public function rota(string $yontem, string $kalip, string $parca, Closure $eylem, ?string $ad = null): void {
        $kalip = implode('', $this->onekler) . $kalip;
        $this->rotalar[] = [$yontem, $kalip, $parca, $eylem];
        if ($ad !== null) $this->adlar[$ad] = $kalip;
    }
    public function url(string $ad, array $parametre = []): string {
        return preg_replace_callback('#\{(\w+)(?::[^}]+)?\}#',
            fn(array $m) => (string) $parametre[$m[1]], $this->adlar[$ad]);
    }
    public function isle(string $yontem, string $yol): Yanit {
        Gunluk::yeniIstek();
        foreach ($this->rotalar as [$y, $kalip, $parca, $eylem]) {     // ilk eşleşen kazanır
            $desen = '#^' . preg_replace_callback('#\{(\w+)(?::([^}]+))?\}#',
                fn(array $m) => '(?P<' . $m[1] . '>' . ($m[2] ?? '[^/]+') . ')', $kalip) . '$#';
            if ($y === $yontem && preg_match($desen, $yol, $m)) {
                Gunluk::yola($parca);
                Gunluk::kostu($parca);
                return $eylem(array_filter($m, 'is_string', ARRAY_FILTER_USE_KEY));
            }
        }
        return new Yanit(404);
    }
}
```

Çekirdek `kostu.php` her derste aynı yirmi iki satırla yeniden verilir. Yönlendirici ona iki çağrıyla bağlanır: eşleşen rotanın adını hem `Gunluk::yola()` hem `Gunluk::kostu()` ile bildirir.

```php
<?php
// kostu.php — beklenen bir parça bu istekte koştu mu?
declare(strict_types=1);

final class Gunluk {
    public static array $yol = [];         // isteğin yoluna konan parçalar
    public static array $kostu = [];       // istek içinde çağrılanlar
    public static array $ertelenen = [];   // isteğin dışına bırakılanlar
    public static function yeniIstek(): void { self::$yol = self::$kostu = self::$ertelenen = []; }
    public static function yola(string $parca): void { self::$yol[] = $parca; }
    public static function kostu(string $parca): void { self::$kostu[] = $parca; }
    public static function ertele(string $parca): void { self::$ertelenen[] = $parca; }
}

function sinifla(string $parca): string {
    return match (true) {
        in_array($parca, Gunluk::$kostu, true) => 'koştu',
        in_array($parca, Gunluk::$ertelenen, true) => 'ertelendi',
        in_array($parca, Gunluk::$yol, true) => 'atlandı',
        default => 'bağlanmadı',
    };
}
```

**ÇT9.** `isle()` içindeki `foreach` rotaları kaydedildikleri sırayla dener ve ilk eşleşende `return` eder. Bu satır bütün dersin kuralıdır: **ilk eşleşen kazanır.** Model, hangi kalıbın daha özel olduğunu bir sıralamayla değerlendirmez; "sabit kalıp parametreli kalıptan önce gelir" diye bir kural da yoktur. Sıra, geliştiricinin `rota()` çağrılarını yazdığı sıradır. Gerçek çerçevelerin bazıları bu kuralı kendi ek sıralamalarıyla yumuşatır; burada ölçülen model yumuşatmaz ve bu bilinçli bir sadeleştirmedir.

## Gruplar ve Adlandırılmış Rotalar

`grup()` bir önek listesiyle çalışır: önek eklenir, grubun içindeki `rota()` çağrıları çalışır ve önek geri alınır. Önek, `rota()` içinde kalıbın başına eklendiği için eşleştirici gruptan habersizdir; yalnızca tam kalıba bakar. Gruplar iç içe yazılabilir ve her kademe kendi önekini ekler. Bu tasarımın bir sonucu vardır: grup yalnızca yazım kolaylığıdır, eşleşmeye yeni bir kural eklemez. `/yazilar` grubunun içinde `/{id}` ile `/yeni` kaydedildiğinde, bu iki kalıp gruptan bağımsız yazılmış `/yazilar/{id}` ve `/yazilar/yeni` ile aynı şekilde davranır.

`url()` ise tersini yapar. Kayıtlı kalıbı alır, her `{parametre}` yerine verilen değeri koyar ve sonucu döndürür. Rota adı kalıba bağlıdır, kalıp ise önekle birlikte saklanmıştır; bu yüzden grubun önekini değiştirmek, adı kullanan her kodun ürettiği adresi birlikte değiştirir. Adlandırılmış rotanın bu dersteki işi bu kadardır: adres üretimini kalıpta tek bir yere bağlar. Hangi rotanın bir isteğe uyacağı hakkında hiçbir söz taşımaz.

## İlk Eşleşen Kazanır

`yonlendirme.php` bir `/yazilar` grubu kurar ve grubun içine iki rota koyar: `/{id}` kalıbıyla `goster` ve `/yeni` kalıbıyla `form`. `kur()` iki kayıt sırası üretir. İlk sırada `goster` önce, `form` sonra kaydedilir. İkinci sırada tersi olur. Çıktıdaki `sonra` ve `önce` sözcükleri `form`'un `goster`'den sonra mı önce mi kaydedildiğini söyler. İki yönlendirici de aynı yola, `/yazilar/yeni` adresine sorulur; geliştiricinin beklediği parça `form`'dur. Grup içindeki `goster` rotası ayrıca `yazilar.goster` adını taşır ve son satır bu addan `id` için `7` değeriyle URL üretir.

```php
<?php
// yonlendirme.php — kayıt sırası hangi rotanın bağlanacağını belirler
declare(strict_types=1);
require_once 'yonlendirici.php';

function kur(bool $yeniOnce): Yonlendirici {
    $y = new Yonlendirici();
    $y->grup('/yazilar', function (Yonlendirici $y) use ($yeniOnce) {
        $form = fn() => new Yanit(200, 'boş form');
        $goster = fn(array $p) => new Yanit(200, "yazı {$p['id']}");
        if ($yeniOnce) $y->rota('GET', '/yeni', 'form', $form);
        $y->rota('GET', '/{id}', 'goster', $goster, ad: 'yazilar.goster');
        if (!$yeniOnce) $y->rota('GET', '/yeni', 'form', $form);
    });
    return $y;
}

foreach (['sonra' => false, 'önce' => true] as $ad => $yeniOnce) {
    $y = kur($yeniOnce);
    $yanit = $y->isle('GET', '/yazilar/yeni');
    printf("yeni %-5s %d %-9s form %s\n", $ad, $yanit->durum, $yanit->govde, sinifla('form'));
}
echo $y->url('yazilar.goster', ['id' => 7]), "\n";
```

```
yeni sonra 200 yazı yeni form bağlanmadı
yeni önce 200 boş form form koştu
/yazilar/7
```

**ÇT10.** Aynı yol, aynı iki rota, tek fark kayıt sırası. `goster` önce kaydedildiğinde `/yazilar/yeni` ona uydu: `{id}` parametresi `yeni` değerini aldı, yanıt 200 oldu ve gövdesi `yazı yeni` çıktı. `form` eylemi **hiç çağrılmadı**; `Gunluk` onu isteğin yoluna koymadı ve karar sırası `$kostu`, `$ertelenen`, `$yol` listelerinde de bulamayınca **bağlanmadı** dedi. `form` önce kaydedildiğinde aynı yol ona uydu ve `boş form` yanıtı geldi: `form` **koştu**. Yanıt iki durumda da 200'dür ve bir hata ya da uyarı çıkmaz; iki durumu yalnızca gövde ve `Gunluk` ayırır.

Sorun bu yüzden sinsidir. Gölgelenen rota kayıtlıdır ve rota tablosunu okuyan biri onu görür. İstek ise ona hiç ulaşmaz ve çerçeve bunu bildirmez; `yazı yeni` yanıtı da bir hata gibi görünmez, çünkü `yeni` geçerli bir `id` değeri gibi okunabilir. Geliştirici bir parçanın koşmadığını yanıtın bir yerinden değil, **beklediği parçayı adlandırıp sorgulayarak** anlar.

Üretilen URL de modelin parçasıdır: son satırdaki `/yazilar/7`, kalıptan türetilmiştir. Adresi elle yazmak yerine adı kullanan kod, kalıp değiştiğinde kırılmaz. Ama adlandırılmış rota yalnızca URL üretir; hangi rotanın bir isteğe uyacağını belirleyen şey yine kayıt sırasıdır.

Bu dersin ölçü sınıfı **bağlanmadı**'dır. Karar sırasının sonuncusu olan bu sınıf, ilk derste en tehlikeli sınıf olarak adlandırılmıştı: atlanan parça bir durum koduyla, ertelenen parça işçide ya da yanıttan sonra görünür, bağlanmayan parça ise hiçbir yerde.

## Rota Tablosunu Okumak

Gölgelenen bir rotayı bulmanın tek güvenilir yolu, o rotanın adını önceden yazıp isteğe sormaktır. Rota tablosunu gözle okuyan biri `form` rotasını kayıtlı görür ve işi bitmiş sanır. `Gunluk` ise tabloyu değil isteği okur: bu istekte `form` yoldaydı mı, çağrıldı mı. İki soru ayrıdır ve yalnızca ikincisi geliştiricinin gerçekte merak ettiği şeydir.

Bu okuma alışkanlığının iki pratik sonucu vardır. Birincisi, yeni bir rota eklemek var olan bir rotayı gölgeleyebilir: sonradan eklenen geniş bir kalıp, kendinden sonra kaydedilmiş bütün dar kalıpları örter. Ekleyenin görmediği bu etki, aynı isteği önce ve sonra ölçmekle yakalanır. İkincisi, bir rotanın koşmadığını anlayan geliştirici ilk olarak eylemin içine bakmaya meyleder; oysa eylem hiç çağrılmamıştır ve içinde aranacak bir şey yoktur. Doğru ilk soru, isteğin hangi rotaya düştüğüdür.

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

Gölgeyi sıra mı doğuruyor? Önceki ölçüm sırayı değiştirince sonucun değiştiğini gösterdi; ama bu, sıranın tek etken olduğunu kanıtlamaz. Sınırlayıcı ölçüm sırayı **değiştirmez**. `goster` yine önce kaydedilir, yalnız kalıbı `{id:\d+}` olarak daraltılır: parametre yalnızca rakamlarla eşleşir. Aynı iki yola sorulur: `/yazilar/yeni` ve `/yazilar/7`.

```php
<?php
// kisit.php — gölgeyi sıra değil kalıbın genişliği doğurur
declare(strict_types=1);
require_once 'yonlendirici.php';

$y = new Yonlendirici();
$y->grup('/yazilar', function (Yonlendirici $y) {
    $y->rota('GET', '/{id:\d+}', 'goster', fn(array $p) => new Yanit(200, "yazı {$p['id']}"));
    $y->rota('GET', '/yeni', 'form', fn() => new Yanit(200, 'boş form'));
});

foreach (['/yazilar/yeni' => 'form', '/yazilar/7' => 'goster'] as $yol => $parca) {
    $yanit = $y->isle('GET', $yol);
    printf("%-14s %d %-9s %s %s\n", $yol, $yanit->durum, $yanit->govde, $parca, sinifla($parca));
}
```

```
/yazilar/yeni  200 boş form form koştu
/yazilar/7     200 yazı 7   goster koştu
```

**ÇT11.** Sıra aynı kaldı ve `form` bu kez **koştu**. `goster` kalıbı artık `yeni` metniyle eşleşmediği için `form` rotasına sıra geldi; `/yazilar/7` ise yine `goster`'e düştü. Gölgeyi doğuran şey sıra değil, **geniş kalıp**tır: `[^/]+` her metni kabul ettiği için `yeni` sözcüğü de ona uyar. Sıra yalnızca iki kalıp birbirini kapsadığında önem kazanır. Kalıp daraltılırsa sıra önemini yitirir.

Bu iki ölçümün birlikte söylediği şudur: bağlanmadığını gördüğünüz bir rota için iki yoldan biri düzeltir ve ikisi aynı sonucu verir. Dar kalıbı geniş kalıptan önce kaydetmek ya da geniş kalıbı daraltmak. İkincisi daha sağlamdır, çünkü sıra değişse bile sonuç değişmez. Birincisi geliştirici dikkatine dayanır ve bir sonraki rota eklendiğinde yeniden bozulabilir.

Bir sınır daha vardır: bu model, varsayılan olarak eğik çizgi içermeyen tek bir yol parçasını eşleştirir; joker ve isteğe bağlı parametre desteklemez. Gerçek çerçevelerin eşleştiricileri bunları ve alan adı kısıtı gibi daha fazlasını destekler; burada ölçülen yalnızca ilk eşleşen kazanır kuralının sonucudur.

## Özet

- Rota yöntem, kalıp, parça adı ve eylemden oluşur; grup ortak bir önek ekler, adlandırılmış rota ise kalıptan URL üretir.
- Modelde ilk eşleşen kazanır ve özgüllük sıralaması yoktur; sıra rotaların kaydedildiği sıradır.
- `/yazilar/{id}` önce kaydedildiğinde `/yazilar/yeni` ona uydu, yanıt 200 ve `yazı yeni` oldu, `form` bağlanmadı; sıra değişince `form` koştu.
- Parametreyi `{id:\d+}` ile daraltmak, sırayı değiştirmeden `form` rotasını koştu sınıfına getirdi; gölgeyi sıra değil kalıbın genişliği doğurur.
- Bu dersin ölçü sınıfı **bağlanmadı**'dır: gölgelenen rota hata vermez, yanıt başarılı görünür ve rota yalnızca adlandırılıp sorgulanınca bulunur.

## Sonraki Adım

Eşleşen rota artık belli: `goster` ya da `form` koştu. Ama rota yalnızca bir eylemi gösterir; eylemin hangi sınıfta durduğu, o sınıfın bağımlılıklarını kimin kurduğu ve yedi eylemli bir kaynağın rotalara nasıl yayıldığı henüz görünmedi. Sonraki ders, Denetleyiciler, rotanın gösterdiği sınıfın nasıl kurulduğunu ve eylemin gerçekten çağrılıp çağrılmadığını soruyor.
