Bağımlılık Otomatik Enjeksiyonu
Webman'da bağımlılık otomatik enjeksiyonu isteğe bağlı bir özelliktir ve varsayılan olarak kapalıdır. Bağımlılık otomatik enjeksiyonuna ihtiyacınız varsa, php-di kullanmanızı öneririz. Aşağıda, Webman ile php-di
'nin nasıl kullanılacağına dair bilgiler bulunmaktadır.
Kurulum
composer require psr/container ^1.1.1 php-di/php-di ^6.3 doctrine/annotations ^1.14
config/container.php
dosyasını düzenleyin. Son hali şöyle olmalıdır:
$builder = new \DI\ContainerBuilder();
$builder->addDefinitions(config('dependence', []));
$builder->useAutowiring(true);
$builder->useAnnotations(true);
return $builder->build();
config/container.php
dosyası sonundaPSR-11
standardına uygun bir konteyner örneği döndürmelidir. Eğerphp-di
kullanmak istemiyorsanız, burada başka birPSR-11
standardına uygun konteyner örneği oluşturup döndürebilirsiniz.
Yapılandırıcı Enjeksiyonu
app/service/Mailer.php
dosyasını oluşturun (dizini yoksa kendiniz oluşturun) ve içerik şöyle olsun:
<?php
namespace app\service;
class Mailer
{
public function mail($email, $content)
{
// E-posta gönderme kodu atlandı
}
}
app/controller/UserController.php
dosyasının içeriği aşağıdaki gibidir:
<?php
namespace app\controller;
use support\Request;
use app\service\Mailer;
class UserController
{
private $mailer;
public function __construct(Mailer $mailer)
{
$this->mailer = $mailer;
}
public function register(Request $request)
{
$this->mailer->mail('hello@webman.com', 'Merhaba ve hoş geldiniz!');
return response('ok');
}
}
Normal şartlarda, app\controller\UserController
'ın örneğini oluşturmak için aşağıdaki koda ihtiyaç vardır:
$mailer = new Mailer;
$user = new UserController($mailer);
php-di
kullanıldığında ise geliştiricilerin kontrolördeki Mailer
'ı manuel olarak örneklemelerine gerek kalmaz, webman bunu otomatik olarak sizin için tamamlayacaktır. Mailer
'ı örneklerken başka sınıfların bağımlılıkları varsa, webman bunları da otomatik olarak örnekleyip enjekte eder. Geliştiricilerin herhangi bir başlangıç işine ihtiyacı yoktur.
Dikkat
Bağımlılık otomatik enjeksyonu yalnızca çerçeve veyaphp-di
tarafından oluşturulan örnekler ile tamamlanabilir, manuel olarak oluşturulannew
örnekleri bağımlılık otomatik enjeksiyonunu tamamlayamaz; eğer enjeksyona ihtiyaç varsa,new
ifadesinisupport\Container
arayüzü ile değiştirmeniz gerekmektedir. Örneğin:
use app\service\UserService;
use app\service\LogService;
use support\Container;
// new anahtar kelimesiyle oluşturulan örnek bağımlılık enjekte edilemez
$user_service = new UserService;
// new anahtar kelimesiyle oluşturulan örnek bağımlılık enjekte edilemez
$log_service = new LogService($path, $name);
// Container ile oluşturulan örnekler bağımlılık enjekte edilebilir
$user_service = Container::get(UserService::class);
// Container ile oluşturulan örnekler bağımlılık enjekte edilebilir
$log_service = Container::make(LogService::class, [$path, $name]);
Notasyon Enjeksiyonu
Yapılandırıcı bağımlılık otomatik enjeksiyonuna ek olarak, notasyon enjeksiyonu da kullanabiliriz. Önceki örneği devam ettirerek, app\controller\UserController
'ı aşağıdaki gibi değiştirelim:
<?php
namespace app\controller;
use support\Request;
use app\service\Mailer;
use DI\Annotation\Inject;
class UserController
{
/**
* @Inject
* @var Mailer
*/
private $mailer;
public function register(Request $request)
{
$this->mailer->mail('hello@webman.com', 'Merhaba ve hoş geldiniz!');
return response('ok');
}
}
Bu örnek, @Inject
notasyonu kullanarak enjekte edilir ve @var
notasyonu ile nesne türü belirtilir. Bu örneğin etkisi, yapılandırıcı bağımlılık otomatik enjeksiyonu ile aynıdır, ancak kod daha özlüdür.
Dikkat
Webman 1.4.6 sürümünden önce kontrolör parametre enjeksiyonunu desteklememektedir; örneğin, aşağıdaki kod webman <= 1.4.6 iken desteklenmemektedir:
<?php
namespace app\controller;
use support\Request;
use app\service\Mailer;
class UserController
{
// 1.4.6 sürümünden önce kontrolör parametre enjeksiyonu desteklenmez
public function register(Request $request, Mailer $mailer)
{
$mailer->mail('hello@webman.com', 'Merhaba ve hoş geldiniz!');
return response('ok');
}
}
Özel Yapılandırıcı Enjeksiyonu
Bazen yapılandırıcıya geçen parametreler, nesne örneği değil de, string, sayı veya dizi gibi veriler olabilir. Örneğin, Mailer yapılandırıcısının smtp sunucu ip ve portunu geçmesi gerekir:
<?php
namespace app\service;
class Mailer
{
private $smtpHost;
private $smtpPort;
public function __construct($smtp_host, $smtp_port)
{
$this->smtpHost = $smtp_host;
$this->smtpPort = $smtp_port;
}
public function mail($email, $content)
{
// E-posta gönderme kodu atlandı
}
}
Bu durumda, önceki yapılandırıcı otomatik enjeksiyonu doğrudan kullanamazsınız çünkü php-di
$smtp_host
ve $smtp_port
değerlerinin ne olduğunu belirleyemez. Bu durumda özel enjeksiyonu denemek gerekir.
config/dependence.php
dosyasına (dosya yoksa kendiniz oluşturun) aşağıdaki kodu ekleyin:
return [
// ... Diğer yapılandırmalar atlandı
app\service\Mailer::class => new app\service\Mailer('192.168.1.11', 25);
];
Böylece bağımlılık enjeksiyonu app\service\Mailer
örneğini alırken bu yapılandırmada oluşturulan app\service\Mailer
örneğini otomatik olarak kullanacaktır.
Görünüşe göre, config/dependence.php
dosyasında new
ile Mailer
sınıfı örneklendirilmiştir. Bu örnek, bu durumda hiçbir sorun yaratmaz. Ancak, Mailer
sınıfı başka sınıflara bağımlıysa veya Mailer
sınıfı içinde notasyon enjeksiyonu kullanılıyorsa, new
ile başlatmak bağımlılık otomatik enjekte etmeyecektir. Çözüm, özel arayüz enjeksiyonu kullanmak ve sınıfı başlatmak için Container::get(class_name)
veya Container::make(class_name, [constructor_parameters])
metodunu kullanmaktır.
Özel Arayüz Enjeksiyonu
Gerçek projelerde, belirli sınıflar yerine arayüzlere yönelik programlama tercih ederiz. Örneğin, app\controller\UserController
içinde app\service\MailerInterface
'i içermelidir, app\service\Mailer
yerine.
MailerInterface
arayüzünü tanımlayın.
<?php
namespace app\service;
interface MailerInterface
{
public function mail($email, $content);
}
MailerInterface
arayüzünün uygulanmasını tanımlayın.
<?php
namespace app\service;
class Mailer implements MailerInterface
{
private $smtpHost;
private $smtpPort;
public function __construct($smtp_host, $smtp_port)
{
$this->smtpHost = $smtp_host;
$this->smtpPort = $smtp_port;
}
public function mail($email, $content)
{
// E-posta gönderme kodu atlandı
}
}
Somut bir uygulama yerine MailerInterface
arayüzünü içeri aktarın.
<?php
namespace app\controller;
use support\Request;
use app\service\MailerInterface;
use DI\Annotation\Inject;
class UserController
{
/**
* @Inject
* @var MailerInterface
*/
private $mailer;
public function register(Request $request)
{
$this->mailer->mail('hello@webman.com', 'Merhaba ve hoş geldiniz!');
return response('ok');
}
}
config/dependence.php
dosyasında MailerInterface
arayüzü kullanılarak uygulanmasına şöyle tanım verin:
use Psr\Container\ContainerInterface;
return [
app\service\MailerInterface::class => function(ContainerInterface $container) {
return $container->make(app\service\Mailer::class, ['smtp_host' => '192.168.1.11', 'smtp_port' => 25]);
}
];
Bu şekilde, iş ihtiyaçları MailerInterface
arayüzünü kullandığında, otomatik olarak Mailer
uygulamasını kullanacaktır.
Arayüze yönelik programlamanın faydası, bir bileşeni değiştirdiğimizde, iş kodunu değiştirmeden yalnızca
config/dependence.php
dosyasındaki somut uygulamayı değiştirerek işimizi halledebilmemizdir. Bu, birim testleri yaparken de oldukça faydalıdır.
Diğer Özel Enjeksiyonlar
config/dependence.php
dosyası sadece sınıf bağımlılıklarını değil, aynı zamanda diğer değerleri de tanımlayabilir; örneğin, string, sayı, dizi gibi.
Örneğin, config/dependence.php
dosyası şu şekilde tanımlanabilir:
return [
'smtp_host' => '192.168.1.11',
'smtp_port' => 25
];
Bu durumda, @Inject
ile smtp_host
ve smtp_port
özelliklerine enjekte edebiliriz.
<?php
namespace app\service;
use DI\Annotation\Inject;
class Mailer
{
/**
* @Inject("smtp_host")
*/
private $smtpHost;
/**
* @Inject("smtp_port")
*/
private $smtpPort;
public function mail($email, $content)
{
// E-posta gönderme kodu atlandı
echo "{$this->smtpHost}:{$this->smtpPort}\n"; // 192.168.1.11:25 olarak çıktıyı verecektir
}
}
Dikkat:
@Inject("key")
içindeki anahtar çift tırnak içinde olmalıdır.
Daha Fazla İçerik
Lütfen php-di belgesi için başvurun.