Menu
Coddy logo textTech

Dependency Injection

Coddy'nin PHP Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 57 / 91.

Önceki derste, kompozisyonun bir Car nesnesinin bir Engine nesnesi içermesine nasıl olanak tanıdığını gördünüz. Ancak bağımlılıkları sınıf içinde oluşturmakla ilgili bir sorun vardır; bu, kodu katı ve test edilmesi zor hale getirir. Dependency Injection, bağımlılıkları dahili olarak oluşturmak yerine dışarıdan aktararak bu sorunu çözer.

Bu iki yaklaşımı karşılaştırın:

<?php
// DI Olmadan - bağımlılık içeride oluşturulur
class Car {
    private Engine $engine;
    
    public function __construct() {
        $this->engine = new Engine(); // Sıkı sıkıya bağlı
    }
}

// DI İle - bağımlılık dışarıdan aktarılır
class Car {
    public function __construct(private Engine $engine) {}
}

$engine = new Engine();
$car = new Car($engine); // Dışarıdan enjekte edildi

İkinci yaklaşım bağımlılık enjeksiyonudur (dependency injection). Car kendi motorunu oluşturmaz - bir tane alır. Bu basit değişikliğin güçlü faydaları vardır: farklı motor tipleri geçirebilir, test için uygulamaları değiştirebilirsiniz ve sınıf daha esnek hale gelir.

Daha fazla esneklik için somut sınıflar yerine arayüzleri enjekte edin:

<?php
interface EngineInterface {
    public function start(): string;
}

class Car {
    public function __construct(private EngineInterface $engine) {}
    
    public function start(): string {
        return $this->engine->start();
    }
}

Artık Car, EngineInterface arayüzünü uygulayan herhangi bir sınıfla çalışır - bir gazlı motor, elektrikli motor veya test için bir mock. Bu ayrıştırma (decoupling), bağımlılık enjeksiyonunun (dependency injection) bakımı kolay, test edilebilir PHP uygulamaları yazmak için neden temel olduğunun sebebidir.

challenge icon

Görev

Kolay

Bağımlılık enjeksiyonunun (dependency injection) gücünü gösteren bir bildirim sistemi oluşturalım. Mesajların nasıl gönderileceğini sabit kodlamak (hardcoding) yerine, gönderim yönteminin kolayca değiştirilebildiği esnek bir sistem oluşturacaksınız.

Kodunuzu dört dosya halinde düzenleyeceksiniz:

  • MessageSenderInterface.php — Tek bir send(string $recipient, string $message): string metoduna sahip MessageSenderInterface adında bir arayüz (interface) tanımlayın. Bu arayüz, herhangi bir mesaj göndericinin uyması gereken sözleşmeyi belirler.
  • EmailSender.phpMessageSenderInterface arayüzünü uygulayan (implement) bir EmailSender sınıfı oluşturun. Arayüz dosyasını dahil edin. send() metodu "Email to $recipient: $message" değerini döndürmelidir.
  • NotificationService.php — Bağımlılığını yapıcı metot (constructor) aracılığıyla alan bir NotificationService sınıfı oluşturun. Arayüz dosyasını dahil edin. Sınıf şunları yapmalıdır:
    • Yapıcı metodunda (constructor promotion kullanarak) bir MessageSenderInterface kabul etmelidir.
    • Enjekte edilen göndericiye yetki devreden ve onun sonucunu döndüren bir notify(string $recipient, string $message) metoduna sahip olmalıdır.
    NotificationService sınıfının somut bir sınıfa değil, arayüzüne nasıl bağımlı olduğuna dikkat edin. Bu, servisi değiştirmeden arayüzü uygulayan herhangi bir göndericiyi enjekte edebileceğiniz anlamına gelir.
  • main.php — EmailSender ve NotificationService dosyalarını dahil edin. İki girdi alacaksınız: bir alıcı ve bir mesaj. Bir EmailSender oluşturun, bunu bir NotificationService içine enjekte edin, ardından notify() metodunu çağırın ve sonucu yazdırın.

Bu desen NotificationService sınıfınızı esnek tutar; ister e-posta, ister SMS, ister henüz oluşturmadığınız başka bir şey olsun, enjekte ettiğiniz her göndericiyle çalışır. Servis kendi bağımlılıklarını oluşturmaz; onları dışarıdan alır.

Kopya kağıdı

Bağımlılık Enjeksiyonu (DI), bağımlılıkların dahili olarak oluşturulmak yerine dışarıdan bir sınıfa aktarıldığı bir tekniktir.

DI olmadan (sıkı bağlı):

<?php
class Car {
    private Engine $engine;
    
    public function __construct() {
        $this->engine = new Engine(); // Created inside
    }
}

DI ile (gevşek bağlı):

<?php
class Car {
    public function __construct(private Engine $engine) {}
}

$engine = new Engine();
$car = new Car($engine); // Injected from outside

Maksimum esneklik için, somut sınıflar yerine arayüzler (interfaces) enjekte edin:

<?php
interface EngineInterface {
    public function start(): string;
}

class Car {
    public function __construct(private EngineInterface $engine) {}
    
    public function start(): string {
        return $this->engine->start();
    }
}

Bu, Car sınıfının EngineInterface arayüzünü uygulayan herhangi bir sınıfla çalışmasına olanak tanıyarak kodu daha sürdürülebilir ve test edilebilir hale getirir.

Kendin dene

<?php
require_once 'EmailSender.php';
require_once 'NotificationService.php';

// Girdiyi oku
$recipient = trim(fgets(STDIN));
$message = trim(fgets(STDIN));

// TODO: Bir EmailSender örneği oluşturun
// TODO: Bunu bir NotificationService içine enjekte edin
// TODO: notify() fonksiyonunu çağırın ve sonucu yazdırın

?>
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler