Laravel'de Inversion of Control (IoC) ve Contextual Binding Kullanımı

L

Laravel, Inversion of Control (IoC) prensibini benimseyerek, bağımlılık yönetimini oldukça esnek hale getirir. IoC, bir sınıfın bağımlılıklarını doğrudan oluşturmak yerine bir container (kap) tarafından yönetilmesini sağlar. Bu sayede bağımlılıklar merkezi olarak tanımlanabilir ve gerektiğinde değiştirilebilir.

Bu yazıda, contextual binding (bağlamsal bağlama) yöntemini kullanarak Laravel'de bağımlılıkları nasıl yöneteceğimizi detaylı ve anlaşılır kod örnekleriyle açıklayacağız.

Inversion of Control Nedir?

Bir sınıfın bağımlılıklarını doğrudan oluşturması yerine, dışarıdan sağlanmasını ifade eder. Bu yaklaşım, yazılımın esnekliğini ve test edilebilirliğini artırır.

Örnek olarak aşağıdaki sınıfı ele alalım:

class FileLogger
{
    public function log($message)
    {
        file_put_contents('log.txt', $message . PHP_EOL, FILE_APPEND);
    }
}

class UserService
{
    protected $logger;

    public function __construct(FileLogger $logger)
    {
        $this->logger = $logger;
    }

    public function registerUser($user)
    {
        // Kullanıcı kayıt işlemleri
        $this->logger->log("Yeni kullanıcı kaydedildi: " . $user);
    }
}

Burada UserService sınıfı FileLogger sınıfına doğrudan bağımlıdır. Eğer farklı bir logger (örneğin veritabanı veya üçüncü taraf bir servis) kullanmak istersek, UserService sınıfını değiştirmemiz gerekir ki bu kötü bir uygulamadır.

IoC kullanarak bağımlılığı dışarıdan sağlayarak bu problemi çözebiliriz.

Laravel IoC Container ile Bağımlılık Yönetimi

Laravel'in service container özelliği ile bağımlılıkları tanımlayabilir ve yönetebiliriz.

Örneğin, yukarıdaki UserService'i IoC Container ile daha esnek hale getirelim:

interface LoggerInterface
{
    public function log($message);
}

class FileLogger implements LoggerInterface
{
    public function log($message)
    {
        file_put_contents('log.txt', $message . PHP_EOL, FILE_APPEND);
    }
}

class DatabaseLogger implements LoggerInterface
{
    public function log($message)
    {
        // Veritabanına log kaydetme işlemi
        echo "Veritabanına kaydedildi: $message";
    }
}

class UserService
{
    protected $logger;

    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }

    public function registerUser($user)
    {
        // Kullanıcı kayıt işlemleri
        $this->logger->log("Yeni kullanıcı kaydedildi: " . $user);
    }
}

Şimdi Laravel'in service container yapısını kullanarak bağımlılıkları yöneteceğiz.

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->bind(LoggerInterface::class, FileLogger::class);
    }
}

Böylece Laravel, LoggerInterface bağımlılığı istendiğinde FileLogger sınıfını enjekte edecektir.

Contextual Binding (Bağlamsal Bağlama) Kullanımı

Eğer belirli bir sınıf için farklı bağımlılıklar kullanmamız gerekirse, contextual binding özelliğini kullanabiliriz.

Örneğin, AdminUserService için DatabaseLogger, UserService için FileLogger kullanmak istiyoruz.

Çözüm: Contextual Binding Kullanımı

Bunu Laravel’de şu şekilde yapabiliriz:

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->when(UserService::class)
            ->needs(LoggerInterface::class)
            ->give(FileLogger::class);

        $this->app->when(AdminUserService::class)
            ->needs(LoggerInterface::class)
            ->give(DatabaseLogger::class);
    }
}

Bu tanımlamalar sayesinde:

  • UserService sınıfı kullanıldığında FileLogger enjekte edilir.
  • AdminUserService sınıfı kullanıldığında DatabaseLogger enjekte edilir.

Böylece bağımlılıklar tamamen esnek ve değiştirilebilir hale gelir.

Tam Çalışan Örnek Senaryo

Şimdi tüm kodları birleştirerek çalışan bir Laravel uygulaması oluşturalım.

Arayüz ve Logger Sınıfları

interface LoggerInterface
{
    public function log($message);
}

class FileLogger implements LoggerInterface
{
    public function log($message)
    {
        file_put_contents('log.txt', $message . PHP_EOL, FILE_APPEND);
    }
}

class DatabaseLogger implements LoggerInterface
{
    public function log($message)
    {
        echo "Veritabanına kaydedildi: $message";
    }
}

Bağımlılığı Kullanan Servisler

class UserService
{
    protected $logger;

    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }

    public function registerUser($user)
    {
        $this->logger->log("Yeni kullanıcı kaydedildi: " . $user);
    }
}

class AdminUserService
{
    protected $logger;

    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }

    public function registerAdmin($admin)
    {
        $this->logger->log("Yeni admin kaydedildi: " . $admin);
    }
}

Contextual Binding ile IoC Container Ayarları

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->when(UserService::class)
            ->needs(LoggerInterface::class)
            ->give(FileLogger::class);

        $this->app->when(AdminUserService::class)
            ->needs(LoggerInterface::class)
            ->give(DatabaseLogger::class);
    }
}

Kullanım

$userService = app(UserService::class);
$userService->registerUser("Aydın");

$adminService = app(AdminUserService::class);
$adminService->registerAdmin("Yağız");
  • UserServiceFileLogger kullanarak logları dosyaya yazacak.
  • AdminUserServiceDatabaseLogger kullanarak veritabanına yazacak.

Sonuç

IoC container ve contextual binding, Laravel'de bağımlılık yönetimini güçlü ve esnek hale getirir.
Bu yöntemleri kullanarak kod tekrarını azaltabilir, test edilebilirliği artırabilir ve uygulamanın farklı bölümleri için farklı bağımlılıkları yönetebiliriz.

Bağımlılık Enjeksiyonu (DI) ve IoC Container kullanımı ile kodlarımız daha sürdürülebilir ve esnek hale gelir! 

By Aydın Yağız

Aydın Yağız

Teknolojiye olan tutkumla inovasyonu destekler, kullanıcı deneyimini önceliklerim arasına alırım. Kendi yeteneklerimi ve bilgilerimi paylaşarak, daha geniş bir topluluğun faydalanmasını sağlarım. İş birliği içinde hareket ederek, geleceğin teknoloji dünyasına katkıda bulunmayı hedeflerim. Sizi de bu heyecan verici yolculuğa davet ediyor, fikirlerinizi paylaşmaya ve teknolojiye dair sınırları zorlamaya teşvik ediyorum. Birlikte büyüyelim ve yeni ufuklara açılalım!

İletişime Geçin

Kodlama dünyasına adım atın ve deneyimlerinizi paylaşın. Siz de bu aktif topluluğa katılarak yeni bağlantılar kurun, fikir alışverişinde bulunun ve bilgi birikiminizi artırın.

Özelleştir

Farklı yazı tipleri ve renk seçenekleriyle stilinizi kişiselleştirin. Aşağıdaki örneklerden birini deneyerek sizin için en uygun olanı seçin.

Yazı Tipi Örnekleri

Renk Örnekleri