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.
Görev
KolayBağı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 birsend(string $recipient, string $message): stringmetoduna sahipMessageSenderInterfaceadında bir arayüz (interface) tanımlayın. Bu arayüz, herhangi bir mesaj göndericinin uyması gereken sözleşmeyi belirler.EmailSender.php—MessageSenderInterfacearayüzünü uygulayan (implement) birEmailSendersı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 birNotificationServicesınıfı oluşturun. Arayüz dosyasını dahil edin. Sınıf şunları yapmalıdır:- Yapıcı metodunda (constructor promotion kullanarak) bir
MessageSenderInterfacekabul etmelidir. - Enjekte edilen göndericiye yetki devreden ve onun sonucunu döndüren bir
notify(string $recipient, string $message)metoduna sahip olmalıdır.
NotificationServicesı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.- Yapıcı metodunda (constructor promotion kullanarak) bir
main.php— EmailSender ve NotificationService dosyalarını dahil edin. İki girdi alacaksınız: bir alıcı ve bir mesaj. BirEmailSenderoluşturun, bunu birNotificationServiceiçine enjekte edin, ardındannotify()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 outsideMaksimum 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
?>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
1OOP Temelleri
Harici DosyalarOOP'ye GirişSınıflar ve Nesneler$this Anahtar KelimesiMetotlarÖzelliklerYapıcı Metot (__construct)Yıkıcı Metot (__destruct)Özet - Basit Hesap Makinesi4Kalıtım
Temel Kalıtımparent:: Anahtar KelimesiMetot Geçersiz Kılmafinal Anahtar KelimesiSoyut SınıflarÖzet - Çalışan Hiyerarşisi7Kapsülleme
Public, Protected, PrivateErişim Belirleyicilere Derinlemesine BakışGetter ve Setter MetotlarıBilgi GizlemeConstructor Promotion (8.0)Özet - Öğrenci Kayıt Sistemi10İleri Düzey OOP Kavramları
Kompozisyon vs KalıtımDependency InjectionAnonim SınıflarEnum'lar (PHP 8.1)Fiber'lar (PHP 8.1)Nesne Klonlama: Derinlemesine İncelemeGenerator'lar ve Iterator'lar13Tasarım Kalıpları Bölüm 2
Komut KalıbıAdaptör KalıbıDekoratör KalıbıŞablon Metot KalıbıDurum KalıbıKompozit KalıbıRepository Kalıbı2İsim Alanları ve Autoloading
İsim Alanlarına Girişuse Anahtar KelimesiPSR-4 Autoloading StandartıComposer AutoloaderÖzet - Düzenli Proje5Arayüzler ve Sözleşmeler
Arayüzlere GirişArayüzleri UygulamaBirden Fazla Arayüz UygulamaArayüz vs Soyut SınıfArayüzler ile Tip BelirlemeÖzet - Şekil Hesaplayıcı8Sihirli Metotlar
Sihirli Metotlara Giriş__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Nesne Klonlama__serialize & __unserializeÖzet - Özel Koleksiyon3Sınıf Özellikleri
Örnek ve Statik ÖzelliklerSınıflarda SabitlerStatik Metotlar ve ÖzelliklerPrivate ve Protected ÖzelliklerReadonly Özellikler (PHP 8.1)Özet - Banka Hesabı Yöneticisi6Çok Biçimlilik
Metot Geçersiz Kılmaya Yeniden BakışArayüzler ile Çok BiçimlilikType Hinting ve Union TypesLate Static BindingÖzet - Ödeme İşlemcisi9Trait'ler
Trait'lere GirişÇoklu Trait KullanımıTrait Çakışma ÇözümüTrait'lerde Soyut MetotlarTrait'ler ve Kalıtım12Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişSingleton KalıbıFactory KalıbıObserver KalıbıStrategy Kalıbı15Final Meydan Okumaları
E-Öğrenme PlatformuBankacılık SistemiOyun Karakteri GeliştirmeAraç Kiralama Servisi