---
title: 'Bağımlılık Enjeksiyonu'
source: 'https://academia.sh/tr/kurslar/php-nesne-modeli/bagimlilik-enjeksiyonu'
course: 'Nesneye Dayalı PHP ve Standartlar'
language: tr
updated: '2026-10-21T05:03:35+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Yapıcıdan enjeksiyonla kurulan bir hizmetin bağımlılığının yalnız kurulum dosyasında değiştiğini ölçer'
    - 'Bağımlılığını içeride kuran hizmetin, bağımlılığın yapıcısı değişince durduğunu karşılaştırır'
    - 'Bağlantı noktasının yalnız sözleşme korunduğu sürece bağlantıda kaldığını gösterir'
    - 'Kurs boyunca ölçülen on iki değişikliği dört sınıfa göre özetler'
---

# Bağımlılık Enjeksiyonu

Yapıcıdan enjeksiyon, arayüze bağımlılık ve el ile bağlama; bir hizmetin bağımlılığının yalnız kurulum dosyasında değişmesi; bağımlılığı içeride kurmanın değişikliği hizmetlere taşıması; bağlantı noktasının sözleşme korunduğu sürece geçerli olması; on iki dersin ölçü tablosu.

Bağımlılık Yöneticisi dersi, kodun bağlı olduğu paketin hangi sürümünün kurulacağını tek bir kilit dosyasında topladı. Sınıfın bağımlılığını ise kim kuruyor? Bu derste soru şu: bir hizmetin ihtiyaç duyduğu nesne değişirse **bu değişiklik nereye ulaşıyor** ve hangi dosya düzenleniyor? M10/K04 bir bileşenin **neye ihtiyaç duyduğunu** sordu; burada ölçülen, o gereksinim değiştiğinde değişikliğin kullananlara ulaşıp ulaşmadığıdır.

## Bağımlılığı Kim Kurar

Bir hizmetin ihtiyaç duyduğu nesneye **bağımlılık** (dependency) denir. Hizmet bağımlılığını iki yoldan edinir: ya kendi içinde `new` ile kurar ya da kurulmuş hâlde dışarıdan alır. İkinci yola **bağımlılık enjeksiyonu** (dependency injection) denir ve PHP'de bir biçimi **yapıcıdan enjeksiyondur**: nesne bağımlılığını yapıcı işlevinin parametresi olarak ister.

İkinci karar, parametrenin tipidir. Hizmet somut bir sınıfın adını değil bir **arayüzün** adını yazarsa, o arayüzü gerçekleştiren her sınıf kabul edilir. Hizmet artık bağımlılığının hangi sınıf olduğunu bilmez, yalnız hangi sözleşmeyi karşıladığını bilir. Nesneleri bir araya getiren işe **bağlama** (wiring) denir ve el ile yapıldığında tek bir yerde, genellikle bir kurulum dosyasında toplanır; bu dosya **bağlantı noktasıdır**.

**ST5.** Ders yalnız yapıcıdan enjeksiyonu ölçer. Özellik ya da yöntem üzerinden enjeksiyon, bir nesne kabının bağımlılıkları kendiliğinden çözmesi ve nesnelerin paylaşılıp paylaşılmaması modellenmez. Ölçümdeki bağlama, bir fonksiyon dizisidir.

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

`yayilim.php` önceki derslerle aynıdır: aynı programı değişiklikten önce ve sonra kurup koşturur. 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;
}
```

## El ile Bağlama: Bağlantıda

Gözlem `el-ile-baglama`: `Profil` hizmeti bir `Depo` ister ve bir adı yazıp geri okur. Tabanda üç dosya var. `depo.php` arayüzü ve `DiziDepo` gerçekleştirimini taşır. `main.php` içindeki `Profil` yapıcısında `Depo` tipli bir parametre ister ve hangi depoyu alacağını bilmez. `kurulum.php` ise bir fonksiyon dizisi döndürür: `depo` anahtarı çağrıldığında bir `DiziDepo` kurar.

O dizi **en küçük nesne kabıdır** (IoC container). Bir ad verirsiniz, kurulmuş nesne alırsınız; nesnenin nasıl kurulduğu yalnız bu dosyada yazılıdır. Aşağıdaki küçük blok, her çağrının yeni bir örnek kurduğunu ve dizinin gerçekleştirimin sınıf adını yalnız burada verdiğini gösterir.

```php
<?php
// kap.php — fonksiyon dizisi en kucuk nesne kabidir
interface Depo
{
    public function oku(string $anahtar): ?string;
}
class DiziDepo implements Depo
{
    public function oku(string $anahtar): ?string { return null; }
}
$kurulum = ['depo' => fn () => new DiziDepo()];
$a = $kurulum['depo']();
$b = $kurulum['depo']();
echo get_class($a), "\n";
echo $a === $b ? 'ayni ornek' : 'ayri ornek', "\n";
```

```
DiziDepo
ayri ornek
```

Değişiklik tek dosyada: `kurulum.php` artık depoyu, yazmaları sayan bir `SayanDepo` ile sarıyor. `Profil` ve `main.php` yerinde duruyor. Sonraki blok tabanı `taban.php` olarak diske yazar; sonraki sürücüler onu çeker. Dördüncü argüman bağlantı listesidir ve `kurulum.php`'yi bağlantı noktası olarak adlandırır.

```php
<?php
// taban.php — Profil, Depo ve kurulum dosyasi
return [
    'depo.php' => <<<'PHP'
        <?php
        interface Depo
        {
            public function yaz(string $anahtar, string $deger): void;
            public function oku(string $anahtar): ?string;
        }
        class DiziDepo implements Depo
        {
            private array $veri = [];
            public function yaz(string $anahtar, string $deger): void { $this->veri[$anahtar] = $deger; }
            public function oku(string $anahtar): ?string { return $this->veri[$anahtar] ?? null; }
        }
        PHP,
    'kurulum.php' => <<<'PHP'
        <?php
        return ['depo' => fn () => new DiziDepo()];
        PHP,
    'main.php' => <<<'PHP'
        <?php
        require 'depo.php';
        class Profil
        {
            public function __construct(private Depo $depo) {}
            public function adAta(string $ad): string { $this->depo->yaz('ad', $ad); return $this->depo->oku('ad'); }
        }
        $kurulum = require 'kurulum.php';
        echo (new Profil($kurulum['depo']()))->adAta('ece'), "\n";
        PHP,
];
```

```php
<?php
// baglama.php — depo kurulum dosyasinda sarilir
require_once 'yayilim.php';

olc('el-ile-baglama', require 'taban.php', [
    'kurulum.php' => <<<'PHP'
        <?php
        class SayanDepo implements Depo
        {
            public int $yazma = 0;
            public function __construct(private Depo $ic) {}
            public function yaz(string $anahtar, string $deger): void { $this->yazma++; $this->ic->yaz($anahtar, $deger); }
            public function oku(string $anahtar): ?string { return $this->ic->oku($anahtar); }
        }
        return ['depo' => fn () => new SayanDepo(new DiziDepo())];
        PHP,
], ['kurulum.php']);

echo kostur('olcum/el-ile-baglama/once')[1], ' -> ', kostur('olcum/el-ile-baglama/sonra')[1], "\n";
```

```
el-ile-baglama     1 dosya  cikis=0   cikti ayni   -> baglantida
ece -> ece
```

İlk satır ölçümün sonucu: bir dosya değişti, çıkış 0 kaldı, çıktı aynı kaldı ve değişen dosya bağlantı listesinde olduğu için sınıf **bağlantıda**. İkinci satır iki sürümün çıktısıdır: `ece` önce de sonra da. `Profil` yeni bir bağımlılık aldığını bilmedi, çünkü yalnız `Depo` tipini tanıyordu. Sayma özelliği, yani hizmete eklenen yeni bir davranış, `Profil` düzenlenmeden geldi.

## Karşıt: Bağımlılığı İçeride Kurmak

Aynı hizmetler bağımlılıklarını kendi yapıcılarında `new DiziDepo()` ile kursaydı, ilk bakışta fark görünmezdi. Fark değişiklikte çıkar. Aşağıdaki tabanda `Profil` ve `Sepet` adlı iki hizmet depolarını kendileri kuruyor ve `DiziDepo`'nun yapıcısı parametresiz. Değişiklik tek dosyada ve yalnız `DiziDepo`'ya dokunuyor: yapıcı bir anahtar öneki istiyor.

```php
<?php
// icerde.php — iki hizmet bagimliligini kendi icinde kuruyor
require_once 'yayilim.php';

olc('icerde-new', [
    'depo.php' => <<<'PHP'
        <?php
        class DiziDepo
        {
            private array $veri = [];
            public function yaz(string $anahtar, string $deger): void { $this->veri[$anahtar] = $deger; }
            public function oku(string $anahtar): ?string { return $this->veri[$anahtar] ?? null; }
        }
        PHP,
    'main.php' => <<<'PHP'
        <?php
        require 'depo.php';
        class Profil
        {
            private DiziDepo $depo;
            public function __construct() { $this->depo = new DiziDepo(); }
            public function adAta(string $ad): string { $this->depo->yaz('ad', $ad); return $this->depo->oku('ad'); }
        }
        class Sepet
        {
            private DiziDepo $depo;
            public function __construct() { $this->depo = new DiziDepo(); }
            public function urunAta(string $urun): string { $this->depo->yaz('urun', $urun); return $this->depo->oku('urun'); }
        }
        echo (new Profil())->adAta('ece'), ' ', (new Sepet())->urunAta('kalem'), "\n";
        PHP,
], [
    'depo.php' => <<<'PHP'
        <?php
        class DiziDepo
        {
            private array $veri = [];
            public function __construct(private string $onek) {}
            public function yaz(string $anahtar, string $deger): void { $this->veri[$this->onek . $anahtar] = $deger; }
            public function oku(string $anahtar): ?string { return $this->veri[$this->onek . $anahtar] ?? null; }
        }
        PHP,
]);

echo kostur('olcum/icerde-new/once')[1], "\n";
```

```
icerde-new         1 dosya  cikis=255 cikti farkli -> kiran
ece kalem
```

Sınıf **kıran**: bir dosya değişti, çıkış 255. Son satır önceki sürümün çıktısıdır; sonraki sürüm hiçbir şey basamadı. `Profil` ve `Sepet` düzenlenmedi ama yapıcıdaki `new DiziDepo()` çağrısı yeni zorunlu parametreyi veremedi ve program durdu. Aynı kalıp her hizmette yinelendiği için bağımlılığın değişimi bu iki hizmetin ikisine de ulaştı. Birincisinde bağımlılığı kuran yer tek bir dosyaydı; burada kuran yer her hizmetin kendi gövdesidir, yani bağlantı noktası hizmet sayısı kadardır.

**ST6.** Karşıt ölçümde kıran sonucu, `DiziDepo` yapıcısına eklenen zorunlu parametreden gelir. Parametre isteğe bağlı olsaydı ya da yapıcı hiç değişmeseydi ölçüm başka sonuç verirdi; ders bunu ölçmez.

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

Bağlantı noktası değişikliği karşıladı, ama her değişikliği karşılamaz. Bağlantının geçerliliği sözleşmeye bağlıdır: `Profil` yapıcısı `Depo` tipini ister. Bu ölçümde `kurulum.php`, `yaz` ve `oku` yöntemlerini taşıyan ama `Depo`'yu gerçekleştirmeyen bir nesne döndürür. Yöntem adları aynıdır; yalnız `implements Depo` yoktur. Taban `el-ile-baglama` tabanıdır ve değişiklik yine yalnız `kurulum.php`'dedir.

```php
<?php
// sozlesme.php — kurulum, Depo'yu gerceklestirmeyen bir nesne dondurur
require_once 'yayilim.php';

olc('sozlesmesiz', require 'taban.php', [
    'kurulum.php' => <<<'PHP'
        <?php
        class SozlukDepo
        {
            private array $veri = [];
            public function yaz(string $anahtar, string $deger): void { $this->veri[$anahtar] = $deger; }
            public function oku(string $anahtar): ?string { return $this->veri[$anahtar] ?? null; }
        }
        return ['depo' => fn () => new SozlukDepo()];
        PHP,
], ['kurulum.php']);
```

```
sozlesmesiz        1 dosya  cikis=255 cikti farkli -> kiran
```

Aynı dosya, aynı bağlantı listesi, ama sınıf **kıran** oldu: çıkış 255. Değişen dosya bağlantı listesindeydi; bu yetmedi, çünkü sıralamada çıkış kodu bağlantıdan önce gelir. `Profil` yapıcısındaki tip bildirimi `SozlukDepo`'yu geri çevirdi. Bu ölçümde ileti basılmadı; durduran düzenek Tip Bildirimleri dersindeki aynı tip denetimidir. `SozlukDepo` doğru yöntemlere sahip olsa da sözleşmeyi bildirmedi. Bağlantı noktası yalnız sözleşme korunduğu sürece değişikliği tek dosyada tutar; sözleşmeyi bozan bir bağlama kullananı durdurur.

**ST7.** `sozlesmesiz` ölçümü bağlama kodunun hatalı olduğu durumu modeller: bir tip bildirimi var ve bağlayan yanlış nesneyi veriyor. Tip bildirimi olmasaydı `Profil` aynı yöntem adlarıyla çalışabilirdi; ders bu durumu ölçmez.

## Özet

- Bağımlılık enjeksiyonu, bir hizmetin ihtiyaç duyduğu nesneyi içeride `new` ile kurmak yerine yapıcısından almasıdır; arayüz tipi hizmeti gerçekleştirimden ayırır.
- Bu dersin ölçü sınıfı **bağlantıda**. `el-ile-baglama` gözleminde depo `kurulum.php` içinde sarıldı, bir dosya değişti, çıkış 0 kaldı ve çıktı `ece` kaldı. Fonksiyon dizisi en küçük nesne kabıdır.
- Karşıtı `icerde-new` **kıran**: iki hizmet depoyu kendi içinde kurduğundan `DiziDepo` yapıcısına parametre eklemek ikisini de durdurdu, çıkış 255.
- Sınırlayıcı ölçüm `sozlesmesiz` **kıran**: `kurulum.php` `Depo`'yu gerçekleştirmeyen bir nesne döndürünce `Profil` yapıcısındaki tip bildirimi durdurdu, çıkış 255.
- Bağlantı noktası yalnız sözleşme korunduğu sürece değişikliği tek dosyada tutar.

## Kurs Kapanışı

Kurs tek bir soruyu on iki kez sordu: **bu değişiklik nereye ulaşıyor?** Her ders çekirdekten tek bir değişiklik aldı ve dört sınıftan birine yerleştirdi. Aşağıdaki tablo her dersin sınıfını `## Özet` bölümünden, sınırlayıcı ölçümünü dersin `## Sınırlayıcı Ölçüm` bölümünden alır.

| Ders | Ölçülen değişiklik | Sınıf | Sınırlayıcı ölçüm |
|---|---|---|---|
| Sınıflar ve Nesneler | özel özelliğin adı | yerinde | public özelliğe yazan kullanan: yerinde, `E_DEPRECATED` |
| Kalıtım ve Soyut Sınıflar | üst sınıf iç çağrıyı bıraktı | örtük | bileşimle sayaç: yerinde, `3` |
| Arayüzler | arayüze yöntem eklendi | kıran | gövdeli soyut sınıf: yerinde, `120` |
| Trait'ler | trait'e çakışan ad eklendi | kıran | sınıfın kendi yöntemi: yerinde |
| Statik Üyeler ve Sabitler | yapıcı imzası, statik fabrika | yerinde | sabit değeri `20` → `18`: örtük, `120` → `118` |
| Sihirli Yöntemler | `__get` anahtarının adı | örtük | bilinmeyen adda istisna: kıran |
| Tip Bildirimleri | parametreye `int` eklendi | kıran | `?int` ve `'5'`: yerinde, `float(0)` ve `float(6)` |
| Ad Alanları | dış kod aynı adlı sınıf ekledi | yerinde | nitelenmemiş `strlen`: örtük, `5` → `0` |
| Otomatik Yükleme | sınıf dosyası taşındı, 3 dosya | bağlantıda | `urun.php` küçük harf: kıran |
| Ortak Arayüz Standartları | gerçekleştirim değişti | bağlantıda | `{no}` doldurulmuyor: örtük |
| Bağımlılık Yöneticisi | alt sürüm yayımlandı, kilitsiz | örtük | `2.0.0` yayımlandı: yerinde |
| Bağımlılık Enjeksiyonu | depo kurulumda sarıldı | bağlantıda | `Depo` olmayan nesne: kıran |

Derslerin dağılımı **3 yerinde · 3 bağlantıda · 3 kıran · 3 örtük**tür. Her ders çekirdekten tek bir gözlem taşıdığı için bu dağılım çekirdeğin on iki değişikliğinin dağılımıyla aynıdır; çekirdeğin kendisi hiçbir derste koşturulup basılmadı, dağılım derslerin sınıf hücrelerinden sayılmıştır.

Tablodan çıkan iki gözlem kursun tezidir. Birincisi, sınıf değişikliğin büyüklüğünden değil, **kullananın neye dokunduğundan** gelir: aynı tanım değişikliği okuyan kullananı örtük, yazan kullananı yerinde bıraktı; aynı yöntem eklemesi gövdesizse kıran, gövdeliyse yerinde oldu. İkincisi, en tehlikeli sınıf **örtük**tür: kıran değişiklik ilk koşumda kendini ele verir, örtük değişiklik ancak sonuca bakılınca görülür. Sınırlayıcı ölçümler her derste sınıfın bir koşula bağlı olduğunu gösterdi; dört sınıf bir tanımın değil, tanımla kullananın arasındaki bağın ölçüsüdür.

Sıradaki kurs M12/K03, Web ile PHP: Oturum, Veri ve Güvenlik. O kurs oturum ve çerezlerin durumu isteklere nasıl taşıdığını, veritabanı erişimini ve parametreli sorguyu, ardından web güvenliğini konu alır. Bu kursun getirdiği ayrım, değişikliğin nereye ulaştığını sınıflandıran dört ad, orada da bir değişikliğin kullananı nasıl etkilediğini okurken işe yarar.
