---
title: 'Otomatik Yükleme'
source: 'https://academia.sh/tr/kurslar/php-nesne-modeli/otomatik-yukleme'
course: 'Nesneye Dayalı PHP ve Standartlar'
language: tr
updated: '2026-10-21T05:03:35+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'spl_autoload_register ile bir ad alanı önekini dizine eşleyen otomatik yükleyici yazar'
    - 'Sınıf dosyası taşındığında yükleyicinin tek bağlantı noktası olarak değişikliği karşıladığını ölçer'
    - 'Dosya sayısının değil kullananın düzenlenip düzenlenmediğinin sınıfı belirlediğini gösterir'
---

# Otomatik Yükleme

spl_autoload_register ile otomatik yükleyici; ad alanı önekinden dizine eşleme ve PSR-4; sınıf dosyasının taşınmasında dosya sayısının sınıfı belirlemediği; yükleyici güncellenmeden yapılan taşımanın programı durdurması; eşlemenin dosya adındaki harf uyumuna bağlılığı.

Ad Alanları dersinde her sınıf `require` ile elle çekildi. Bu, kullananın sınıfın hangi dosyada durduğunu bildiği anlamına gelir; sınıf dosyası taşınırsa bilgi her `require` satırında eskir. Bu derste aynı bilgi tek bir yere toplanıyor: **otomatik yükleyici**. Soru yine kurs boyunca sorulan soru: **bu değişiklik nereye ulaşıyor?**

M09/K02 kursu bir adın bağlandığı yeri arıyordu. Yükleyici, ad ile dosya yolu arasındaki bağın kurulduğu yerdir. Bu derste o bağ değişince kaç dosyanın düzenlendiği ve düzenlenmemiş kodun ne yaşadığı ölçülür.

## Elle Yükleme ve Bedeli

Yükleyiciden önce her sınıf dosyası `require_once` ile elle çekilirdi. Bu yöntemin iki bedeli vardır. Birincisi, kullanan dosya kullandığı her sınıfın yolunu bilmek zorundadır; yol değişirse her `require_once` satırı eskir. İkincisi, satırlar sınıf kullanılsın ya da kullanılmasın çalışır: bir programın yalnız bir sınıfa ihtiyacı olsa da dördünü birden yükler. Sınıfların kendi içinde de başka sınıflara ihtiyaç duyması, bu satırları zincire çevirir ve zincirin hangi sırayla kurulacağı da kullananın yükü olur.

Bedelin ikinci yarısı sayılabilir. Aşağıdaki sürücü dört boş sınıf dosyası yazar ve iki ayrı program kurar: biri dört dosyayı elle çeker, öteki bir yükleyici kaydeder. İkisi de yalnız `A` sınıfını kullanır ve sonunda kaç dosyanın yüklendiğini basar.

```php
<?php
// zincir.php — elle yukleme her dosyayi yukler, yukleyici yalniz kullanilani
mkdir('olcum/zincir/src', 0777, true);
foreach (['A', 'B', 'C', 'D'] as $ad) {
    file_put_contents("olcum/zincir/src/$ad.php", "<?php\nclass $ad {}\n");
}

$elle = <<<'PHP'
    <?php
    require_once 'src/A.php';
    require_once 'src/B.php';
    require_once 'src/C.php';
    require_once 'src/D.php';
    new A();
    echo count(get_included_files()) - 1, "\n";
    PHP;
$otomatik = <<<'PHP'
    <?php
    spl_autoload_register(fn (string $sinif) => require __DIR__ . "/src/$sinif.php");
    new A();
    echo count(get_included_files()) - 1, "\n";
    PHP;
file_put_contents('olcum/zincir/elle.php', $elle);
file_put_contents('olcum/zincir/otomatik.php', $otomatik);

foreach (['elle', 'otomatik'] as $ad) {
    echo str_pad($ad, 9), exec("php olcum/zincir/$ad.php"), " dosya\n";
}
```

```
elle     4 dosya
otomatik 1 dosya
```

Elle yazılan sürüm program yalnız `A` istediği hâlde dört dosya yükledi. Yükleyicili sürüm bir dosya yükledi: `B`, `C` ve `D` hiç istenmedi, hiç açılmadı. Sınıf sayısı büyüdükçe fark da büyür; üç yüz sınıflı bir uygulamada her istek yalnız dokunduğu sınıfların dosyasını okur.

## Yükleyici Ne Zaman Çağrılır

`spl_autoload_register` bir fonksiyonu yükleyici olarak kaydeder. PHP bilmediği bir sınıf adıyla karşılaşınca bu fonksiyonu sınıfın tam nitelikli adıyla çağırır; fonksiyon dosyayı yüklemekle yükümlüdür. Sınıf zaten tanımlıysa ya da çağrı yükleyiciyi atlıyorsa fonksiyon çalışmaz.

```php
<?php
// gozlem.php — yukleyici yalniz bilinmeyen sinif icin cagrilir
spl_autoload_register(function (string $sinif): void {
    echo "istenen: $sinif\n";
});

var_dump(class_exists('Magaza\Model\Urun'));
var_dump(class_exists('Magaza\Model\Urun', false));
echo "bitti\n";
```

```
istenen: Magaza\Model\Urun
bool(false)
bool(false)
bitti
```

İlk `class_exists` yükleyiciyi tam nitelikli adla çağırdı. Bu örnekte yükleyici hiçbir dosya yüklemediği için sınıf yine bulunamadı ve sonuç `false` oldu. İkinci çağrı ikinci argümanla yükleyiciyi atladı: fonksiyon hiç çalışmadı. Yükleyici bir bildirim değil bir geri çağrıdır; PHP onu yalnız eksik sınıf için ve yalnız o an çağırır.

## Yükleyiciyi Hangi İşlemler Çağırır

Yükleyici, PHP'nin bir sınıf adını çözmesi gereken ve sınıfı henüz bilmediği her yerde çağrılır. Bu, kabaca sınıfın var olmasına gerçekten ihtiyaç duyan işlemlerdir: `new`, statik çağrı, sınıf sabiti, `class_exists`. Sınıfın var olmasını gerektirmeyen işlemler ise yükleyiciyi çağırmaz: `instanceof`, `::class` ve parametre tip bildirimi. Aşağıdaki sürücü yükleyiciyi sınıf yüklemeyen bir fonksiyon olarak kaydeder, böylece her işlemden sonra yükleyicinin çağrılıp çağrılmadığı görülür. Bulunamayan sınıf `Error` fırlatır; sürücü hatayı yakalayıp devam eder.

```php
<?php
// tetik.php — yukleyiciyi hangi islemler cagirir
spl_autoload_register(function (string $sinif): void {
    echo "  yukleyici: $sinif\n";
});

function dene(string $ad, callable $islem): void
{
    echo "$ad\n";
    try {
        $islem();
    } catch (Error) {
    }
}

dene('new', fn () => new Bir());
dene('statik cagri', fn () => Iki::calistir());
dene('sinif sabiti', fn () => Uc::SABIT);
dene('class_exists', fn () => class_exists('Dort'));
dene('instanceof', fn () => new stdClass() instanceof Bes);
dene('::class', fn () => Alti::class);
dene('tip bildirimi', function () {
    (fn (Yedi $parametre) => 1)(1);
});
```

```
new
  yukleyici: Bir
statik cagri
  yukleyici: Iki
sinif sabiti
  yukleyici: Uc
class_exists
  yukleyici: Dort
instanceof
::class
tip bildirimi
```

İlk dört işlem yükleyiciyi çağırdı ve sınıf adını aldı. Son üç işlem çağırmadı. `instanceof` karşılaştırılan sınıf yoksa nesnenin o sınıftan olamayacağını biliyor, sınıfı yüklemeye gerek duymuyor. `::class` yalnız derleme anında çözülmüş adı döndürüyor. Tip bildirimi ise kontrolü nesnenin sınıf adıyla yapıyor; yanlış tipte bir değer gelirse `TypeError` fırlatır ama yükleyici yine çağrılmaz. Sonuç şu: bir sınıf yalnız ilk gerçekten kullanıldığında yüklenir. Bu da bir kod yolunun hiç çalışmadığı bir istekte, o yoldaki sınıfların hiç yüklenmediği anlamına gelir.

## Birden Çok Yükleyici

`spl_autoload_register` birden çok kez çağrılabilir. Kayıtlı yükleyiciler kayıt sırasıyla çağrılır ve sınıf tanımlanır tanımlanmaz zincir durur. Üçüncü argüman `true` ise yükleyici sıranın başına eklenir. Bir uygulama kendi yükleyicisine ek olarak bağımlılıkların kendi yükleyicisini de taşıyabilir; bu yüzden her yükleyici yalnız kendi önekini işlemeli, tanımadığı adı hata vermeden bırakmalıdır.

```php
<?php
// sira.php — yukleyiciler kayit sirasiyla cagrilir, sinif bulununca zincir durur
spl_autoload_register(function (string $sinif): void { echo "birinci: $sinif\n"; });
spl_autoload_register(function (string $sinif): void {
    echo "ikinci: $sinif\n";
    if ($sinif === 'Hedef') {
        class_alias(stdClass::class, 'Hedef');
    }
});
spl_autoload_register(function (string $sinif): void { echo "ucuncu: $sinif\n"; });
spl_autoload_register(function (string $sinif): void { echo "basa: $sinif\n"; }, true, true);

echo "-- Hedef\n";
class_exists('Hedef');
echo "-- Yok\n";
class_exists('Yok');
```

```
-- Hedef
basa: Hedef
birinci: Hedef
ikinci: Hedef
-- Yok
basa: Yok
birinci: Yok
ikinci: Yok
ucuncu: Yok
```

`basa` en son kaydedildi ama `true` ile en öne alındığı için ilk o çağrıldı. `Hedef` için zincir ikinci yükleyicide durdu: o `Hedef` adını tanımladı ve `ucuncu` hiç çağrılmadı. `Yok` için hiçbir yükleyici sınıfı tanımlamadı, bu yüzden dördü de sırayla çağrıldı ve sınıf yine bulunamadı. Her yükleyicinin çağrılması bir bedeldir; öneki tanımayan yükleyicinin ilk satırda dönmesi bu yüzden önemlidir.

## Önekten Dizine Eşleme

Yükleyicinin işi tam nitelikli adı dosya yoluna çevirmektir. PHP topluluğunun standart önerisi **PSR-4** bunu kısa bir kurala bağlar: ad alanının bir öneki bir temel dizine karşılık gelir, önekten sonra kalan ad alanı bölümleri alt dizin olur, son bölüm dosya adıdır ve sonuna `.php` eklenir. `Magaza\Model\Urun` sınıfı, `Magaza\` önekine `src/` dizini eşlenmişse `src/Model/Urun.php` dosyasından yüklenir.

**ST2.** Bu ders yükleyiciyi tek önek ve tek temel dizinle kurar. Birden çok önekli ya da yedek dizinli eşlemeler ve ad alanı olmayan eski sınıf adları ölçülmez.

Eşleme dört adımda okunur: önek çıkarılır, kalan göreli ad alınır, ad alanı ayracı dizin ayracına çevrilir ve sona `.php` eklenir. Aşağıdaki sürücü bu dört adımı `Magaza\Model\Urun` adı üzerinde ayrı ayrı basar.

```php
<?php
// psr4.php — PSR-4 eslemesi adim adim
$onek = 'Magaza\\';
$temel = 'src/';
$sinif = 'Magaza\Model\Urun';

echo "tam ad       : $sinif\n";
$goreli = substr($sinif, strlen($onek));
echo "goreli ad    : $goreli\n";
$yol = str_replace('\\', '/', $goreli);
echo "dizin ayraci : $yol\n";
echo "dosya        : $temel$yol.php\n";
```

```
tam ad       : Magaza\Model\Urun
goreli ad    : Model\Urun
dizin ayraci : Model/Urun
dosya        : src/Model/Urun.php
```

Her satır bir önceki satırdan türüyor ve hiçbirinde dosya sistemine bakılmıyor: eşleme salt bir dize işlemidir. Sınıfın dosyada gerçekten tanımlı olup olmadığını yalnız `require` sonrası bilebiliriz. Bu yüzden iyi bir yükleyici `require`'dan önce dosyanın varlığına bakar; dosya yoksa hata vermez ve zincirdeki sonraki yükleyiciye şans tanır. Bu dersin `yukleyici.php`'si ölçümü sade tutmak için bu denetimi yapmaz.

## Ölçüm Düzeneği

`yayilim.php` önceki derste olduğu gibi `olc()` fonksiyonunu taşır: aynı programı değişiklikten önce ve sonra kurup koşturur. Sınıfı sırayla sorar: çıkış 0 değilse **kıran**, çıktı farklıysa **örtük**, düzenlenen dosya bağlantı listesindeyse **bağlantıda**, hiçbiri değilse **yerinde**. Önceki sürüm 0 ile çıkmalıdır ve kullanan `main.php` düzenlenmez.

```php
<?php
// yayilim.php — bir degisikligin nereye ulastigini olcen yardimcilar

function yaz(string $dizin, array $dosyalar): void
{
    foreach ($dosyalar as $ad => $icerik) {
        if ($icerik === null) {
            continue; // null: dosya silindi
        }
        $yol = "$dizin/$ad";
        if (!is_dir(dirname($yol))) {
            mkdir(dirname($yol), 0777, true);
        }
        file_put_contents($yol, $icerik);
    }
}

function oku(string $dizin): array
{
    $dosyalar = [];
    $gezgin = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($dizin, FilesystemIterator::SKIP_DOTS)
    );
    foreach ($gezgin as $dosya) {
        $ad = substr($dosya->getPathname(), strlen($dizin) + 1);
        $dosyalar[$ad] = file_get_contents($dosya->getPathname());
    }
    return $dosyalar;
}

function kostur(string $dizin): array
{
    $komut = 'cd ' . escapeshellarg($dizin) . ' && php -d display_errors=0 main.php 2>/dev/null';
    exec($komut, $satirlar, $kod);
    return [$kod, implode("\n", $satirlar)];
}

function olc(string $ad, array $taban, array $degisiklik, array $baglanti = []): string
{
    if (array_key_exists('main.php', $degisiklik)) {
        throw new LogicException("$ad: kullanan duzenlenmez");
    }
    yaz("olcum/$ad/once", $taban);
    yaz("olcum/$ad/sonra", array_merge($taban, $degisiklik));
    [$kodOnce, $ciktiOnce] = kostur("olcum/$ad/once");
    [$kodSonra, $ciktiSonra] = kostur("olcum/$ad/sonra");
    if ($kodOnce !== 0) {
        throw new LogicException("$ad: taban calismadi");
    }
    $sinif = match (true) {
        $kodSonra !== 0 => 'kiran',
        $ciktiOnce !== $ciktiSonra => 'ortuk',
        array_intersect(array_keys($degisiklik), $baglanti) !== [] => 'baglantida',
        default => 'yerinde',
    };
    printf(
        "%-18s %d dosya  cikis=%-3d cikti %-6s -> %s\n",
        $ad,
        count($degisiklik),
        $kodSonra,
        $ciktiOnce === $ciktiSonra ? 'ayni' : 'farkli',
        $sinif
    );
    return $sinif;
}
```

## Taşıma: Üç Dosya, Bağlantıda

Gözlem `otomatik-yukleme`: `Magaza\Model\Urun` sınıfı `src/Model/Urun.php` dosyasında duruyor ve `yukleyici.php` onu `src/` altında arıyor. Sınıf `kaynak/` temel dizinine taşınıyor. Üç dosya değişiyor: eski dosya siliniyor (değeri `null`), yenisi ekleniyor, yükleyici yeni dizini gösterecek biçimde güncelleniyor. Dördüncü argüman bağlantı listesidir ve `yukleyici.php`'yi bağlantı noktası olarak adlandırır. Karşıtı `yukleyicisiz`: aynı taşıma, yükleyici güncellenmeden.

Tabandaki `yukleyici.php` eşlemeyi üç adımda kurar. Gelen ad `Magaza\` ile başlıyorsa işleme girer, aksi hâlde başka bir yükleyiciye bırakır. Önekten sonra kalan `Model\Urun` kısmındaki ters eğik çizgiler düz eğik çizgiye çevrilir ve sona `.php` eklenir. Ortaya çıkan `Model/Urun.php` yolu, `src/` temel dizininin altında aranır. Temel dizin yükleyicide tek bir dizgi olarak durur; sınıf dosyalarının nereden yükleneceğine dair bütün bilgi orada toplanmıştır. Bu yüzden taşıma, kullananda değil yalnız bu dizgide görünür.

```php
<?php
// yukleme.php — sinif dosyasi tasinir, yukleyici guncellenir ya da guncellenmez
require_once 'yayilim.php';

// 9. Sinif dosyasi baska bir kok dizine tasinir
$siniflar[] = olc('otomatik-yukleme', [
    'src/Model/Urun.php' => <<<'PHP'
        <?php
        namespace Magaza\Model;
        class Urun
        {
            public function ad(): string { return 'kalem'; }
        }
        PHP,
    'yukleyici.php' => <<<'PHP'
        <?php
        spl_autoload_register(function (string $sinif): void {
            $onek = 'Magaza\\';
            if (str_starts_with($sinif, $onek)) {
                require 'src/' . str_replace('\\', '/', substr($sinif, strlen($onek))) . '.php';
            }
        });
        PHP,
    'main.php' => <<<'PHP'
        <?php
        require 'yukleyici.php';
        echo (new Magaza\Model\Urun())->ad(), "\n";
        PHP,
], [
    'src/Model/Urun.php' => null,
    'kaynak/Model/Urun.php' => <<<'PHP'
        <?php
        namespace Magaza\Model;
        class Urun
        {
            public function ad(): string { return 'kalem'; }
        }
        PHP,
    'yukleyici.php' => <<<'PHP'
        <?php
        spl_autoload_register(function (string $sinif): void {
            $onek = 'Magaza\\';
            if (str_starts_with($sinif, $onek)) {
                require 'kaynak/' . str_replace('\\', '/', substr($sinif, strlen($onek))) . '.php';
            }
        });
        PHP,
], ['yukleyici.php']);

echo kostur('olcum/otomatik-yukleme/once')[1], ' -> ', kostur('olcum/otomatik-yukleme/sonra')[1], "\n";

$once = oku('olcum/otomatik-yukleme/once');
olc('yukleyicisiz', $once, [
    'src/Model/Urun.php' => null,
    'kaynak/Model/Urun.php' => $once['src/Model/Urun.php'],
]);
```

```
otomatik-yukleme   3 dosya  cikis=0   cikti ayni   -> baglantida
kalem -> kalem
yukleyicisiz       2 dosya  cikis=255 cikti farkli -> kiran
```

İlk satır `otomatik-yukleme`: üç dosya değişti, çıkış 0 kaldı, çıktı `kalem` iken `kalem` kaldı. Çıktı değişmediği ve düzenlenen dosyalardan biri bağlantı listesinde olduğu için sınıf **bağlantıda**: değişiklik tek bir noktada karşılandı ve `main.php` düzenlenmedi. İkinci satır karşıtı: yükleyici güncellenmeden yapılan aynı taşıma iki dosyayla bitti, ama çıkış 255 verdi ve sınıf **kıran** oldu; yükleyici sınıfı hâlâ `src/` altında arıyordu.

Sonuç şu: dosya sayısı sınıfı belirlemez. Üç dosya değişen taşıma sorunsuzdu, iki dosya değişen taşıma programı durdurdu. Belirleyen, kullananın düzenlenip düzenlenmediği ve bağın tutulduğu tek noktanın güncel olup olmadığıdır.

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

Eşleme, sınıf adının harflerini dosya adına olduğu gibi aktarır. `Urun` sınıfı için yükleyici `Urun.php` dosyasını ister. Sınıf dosyası `urun.php` diye küçük harfle yeniden adlandırılırsa ne olur? Sürücü bu değişikliği aynı tabanda, yükleyiciye dokunmadan ölçer.

```php
<?php
// harf.php — dosya adindaki harf uyumu eslemenin parcasidir
require_once 'yayilim.php';

$once = oku('olcum/otomatik-yukleme/once');
olc('kucuk-harf', $once, [
    'src/Model/Urun.php' => null,
    'src/Model/urun.php' => $once['src/Model/Urun.php'],
]);
```

```
kucuk-harf         2 dosya  cikis=255 cikti farkli -> kiran
```

Sınıf **kıran** oldu: iki dosya değişti, çıkış 255. Yükleyici `Urun.php` istedi, dizinde yalnız `urun.php` vardı. Bu, dilin değil dosya sisteminin sonucudur: sandbox'ın dosya sistemi büyük ve küçük harfi ayırır. Büyük-küçük harf ayırmayan bir dosya sisteminde aynı değişiklik çalışabilir; ders bunu ölçmedi ve yalnız sandbox sonucunu basıyor. Eşleme bu yüzden dosya adının sınıf adıyla harfi harfine aynı olmasını da şart koşar.

## Özet

- Bu dersin ölçü sınıfı **bağlantıda**. `otomatik-yukleme` gözleminde sınıf dosyası başka kök dizine taşındı, üç dosya değişti, çıktı `kalem` kaldı ve değişiklik `yukleyici.php` noktasında karşılandı.
- Karşıtı `yukleyicisiz` **kıran**: yükleyici güncellenmeden iki dosyalık taşıma çıkış 255 verdi. Dosya sayısı sınıfı belirlemez.
- Yükleyici bilinmeyen sınıf için tam nitelikli adla çağrılır; PSR-4 öneki bir dizine eşler, kalan ad alanı bölümleri alt dizin, son bölüm dosya adı olur.
- Yükleyici yalnız sınıfın var olmasını gerektiren işlemlerde (`new`, statik çağrı, sınıf sabiti, `class_exists`) çağrılır; `instanceof`, `::class` ve tip bildirimi onu çağırmaz. Birden çok yükleyici kayıt sırasıyla çalışır ve sınıf bulununca zincir durur.
- Sınırlayıcı ölçüm: dosya `urun.php` diye yeniden adlandırılınca sandbox'ta sınıf **kıran** oldu; bu dosya sisteminin sonucudur.

## Sonraki Adım

Yükleyici, sınıfın nereden geldiğini tek bir yerde topladı. Sınıfın içi ise hâlâ bir arayüzün arkasında değişebilir: kullanan bir arayüze bağlıysa ve gerçekleştirim değişirse kaç yer düzenlenir? Ortak Arayüz Standartları dersi bunu ölçüyor.
