Впровадження залежностей (англ. Dependency Injection, DI) - процес надання зовнішньої залежності програмному компоненту.
Є специфічною формою “інверсії управління” (англ. Inversion of control, IoC), коли вона застосовується до управління
залежностями.
Насправді цей шаблон ми вже використовували в наших прикладах. Ми оголошували залежність класу через типізацію аргументу конструктора:
class MySuperClass
{
private $myClass;
public function __construct(MyClass $class)
{
$this->myClass = $class;
}
}
Якщо Клас використовує певний набір параметрів, які можуть змінюватися, і його робота залежить від цих параметрів, вони повинні встановлюватися не в класі, а поза його межами. Таким чином, кожен раз при зміні параметрів налаштувань Ви не повинні лізти в код класу, щоб змінити їх.
Якщо подивитися в тест, ми побачимо, що ми тестуємо тільки клас Worker
. Він залежить від інтерфейсу “BurgerInterface”.
Якби ми захардкодили залежність прямо в конструкторі:
public function __construct()
{
$this->myClass = new MyClass();
}
Для тестування нам знадобиться:
- реалізувати інтерфейс;
- протестувати клас реалізації;
- протестувати клас Worker.
Так як ми використовуємо DI, ми можемо просто замокати об’єкт типу BurgerInterface
. Це дасть нам впевненість
у працездатності саме нашого класу Worker
, без будь-яких інших.
-
BurgerInterface.php
<?php namespace DesignPatterns\Structural\DependencyInjection; /** * Interface BurgerInterface * @package DesignPatterns\Structural\DependencyInjection */ interface BurgerInterface { /** * @return array */ public function getBurger(): array; }
-
Worker.php
<?php namespace DesignPatterns\Structural\DependencyInjection; /** * Class Worker * @package DesignPatterns\Structural\DependencyInjection */ class Worker { /** * @var BurgerInterface */ protected $burger; /** * Worker constructor. * * @param BurgerInterface $burger */ public function __construct(BurgerInterface $burger) { $this->burger = $burger; } /** * @return array */ public function getBurger(): array { return $this->burger->getBurger(); } }
Test case:
DependencyInjectionTest.php
<?php
namespace DesignPatterns\Tests\Structural\DependencyInjection;
use DesignPatterns\Structural\DependencyInjection\Worker;
class DependencyInjectionTest extends \PHPUnit_Framework_TestCase
{
protected $cheeseburgerReturnDataFixture = [
'muffin' => 'muffin',
'meat' => 'chicken',
'sauce' => 'mayonnaise',
'withCheese' => true,
];
protected $hamburgerReturnDataFixture = [
'muffin' => 'muffin',
'meat' => 'beef',
'sauce' => 'ketchup',
'withCheese' => false,
];
public function testWorkerMakeHamburger()
{
$mockHamburger = $this->createMock(
'DesignPatterns\Structural\DependencyInjection\BurgerInterface'
);
$mockHamburger->expects($this->any())
->method('getBurger')
->will($this->returnValue($this->hamburgerReturnDataFixture));
$worker = new Worker($mockHamburger);
$burger = $worker->getBurger();
$this->assertEquals($this->hamburgerReturnDataFixture, $burger);
}
public function testWorkerMakeCheeseburger()
{
$mockCheeseburger = $this->createMock(
'DesignPatterns\Structural\DependencyInjection\BurgerInterface'
);
$mockCheeseburger->expects($this->any())
->method('getBurger')
->will($this->returnValue($this->cheeseburgerReturnDataFixture));
$worker = new Worker($mockCheeseburger);
$burger = $worker->getBurger();
$this->assertEquals($this->cheeseburgerReturnDataFixture, $burger);
}
}