Hatsune-Miku
@Hatsune-Miku
Няшк :3

Правильно ли я использую PHP-DI?

Сам DI - php-di.org
Вроде бы я понял суть паттерна, но не понял как его применять...

Например вот такой код (Упрощённый и собранный в кучу для примера):

<?php
require_once '../vendor/autoload.php';

use DI\ContainerBuilder;

$di = ContainerBuilder::buildDevContainer();

$di->set('db', new class {
	public function getRow ()
	{
		return [
			'name'   => 'MyName',
			'family' => 'MyFamily',
			'age'    => '17'
		];
	}
});

abstract class BaseController
{
	protected $di;

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

	abstract function indexAction ();
}

class Controller extends BaseController
{
	public function indexAction ()
	{
		$row = $this->di->get('db')->getRow();

		// Пример всё таки, не прикручивать же для него шаблонизатор
		echo 'Name: ',$row['name'],'<br> Family: ',$row['family'],'<br> Age: ',$row['age'];
	}
}

$controller = new Controller($di);
$controller->indexAction();


Правилен ли подход в целом? И ещё, меня смущает вот это:

$row = $this->di->get('db')->getRow();

Хочется попроще как то так:

$row = $this->db->getRow();

Как это сделать с PHP-DI? И возможно ли вообще?
  • Вопрос задан
  • 2455 просмотров
Пригласить эксперта
Ответы на вопрос 3
Fesor
@Fesor
Full-stack developer (Symfony, Angular)
нет, вы не правильно уловили идею. Передавать весь контейнер в качестве зависимости это нарушение этого самого паттерна и принципа инверсии зависимостей. Так можно делать только в случае циклических зависимостей либо же просто как альтернатива ленивой инициализации сервисов (хотя альтернатива так себе, а циклических зависимостей надо избегать).

1) читаем про принцип инверсии зависимостей
2) читаем про внедрение зависимостей
3) если уж используете безымянные классы то они должны имплементить какой-то интерфейс или же экстендиться от какого-то класса.

Вместо того что вы хотите должно быть:

class Foo {
     private $db;

     public function __construct(Connection $connection) {
           $this->db = $connection;
     }

     public function makeFoo() {
          return $this->db->getRows(); // как вы и хотели
     }
}

// а это уже дергаем в конструкторе
$foo = $di->get(Foo::class);
$foo->makeFoo();


то есть в контроллерах мы дожны дернуть сервис который вернет нам готовые данные.
Ответ написан
@xfg
Неправильно. Внедряйте зависимости, а не контейнер. Вы нарушаете Закон Деметры. Будут те же самые проблемы при классическом подходе к юнит-тестированию, как если бы вы вообще ничего не внедряли и инстанциировали все зависимости прямо в классе.
Ответ написан
Комментировать
dmitriylanets
@dmitriylanets
веб-разработчик
в Falcon успешно используется такой подход docs.phalconphp.ru/ru/latest/reference/di.html
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы