Внедрение зависимостей (англ. 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);
}
}