BLOG

ブログ

マブスバックエンドMTG#6 – DI・DIコンテナとは何者だろう?

こんにちは、タロウです。

先日開催した第6回-社内勉強会の様子を紹介します!

今回は・・

全員参加の会でした!

前回まではバックエンドのみとしていましたが、
その垣根をなくし、全員が参加可能な勉強会と改め開催しました!

テーマ

「DIとDIコンテナについて」
Speaker: かねおかさん

コーディング時のデザインパターンを概念から理解する機会は、
なかなか少ないのではないでしょうか?

既存改修や、ベースができているようなプロジェクトにおいても、
取り入れられているケースがあるので、
「こういうことができるんだ!」の一つの知識として
覚えておけるテーマでした!

DIとは何だろう?

まずは言葉の意味から把握しました。
直訳だとなかなか・・難しいですね。

コード例をもとに理解してみる

PHPのコード例をもとにDIパターンではないケースとDIパターンのケースを比較して、
デメリットを解消するコードを知ることができました!

DIパターンではないケース

<?php

class UserController extends Controller
{
	public function index()
	{
		$model = new UserModel();
		$user = $model->getById(1);
		...
	}
	...
}

class UserModel extends Model
{
	public function getById($id)
	{
		$db = new MySqlConnect();
		$query = $db->query('select * from users where id = ?', $id);
		$user = $query->getResult();
		...
		return $user;
	}
	...
}

class MySqlConnect {
	...
}

ここで考えられるデメリットを整理し、
DIパターンでどのように改善できるかを見てみます!

DIパターンのケース

<?php

class UserController extends Controller
{
	public function index()
	{
		$db = new MySqlConnect();
		$model = new UserModel($db);
		$user = $model->getById(1);
		...
	}
	...
}

class UserModel extends Model
{
	protected $db;

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

	public function getById($id)
	{
		$query = $this->db->query('select * from users where id = ?', $id);
		$user = $query->getResult();
		...
		return $user;
	}
	...
}

class MySqlConnect {
	...
}

このように密結合を回避して、それぞれのインスタンスが修正による影響を受けないような作りにすることができました。

コード例では、生成したインスタンスをコンストラクタでセットしているので、
コンストラクタ注入(コンストラクタ・インジェクション)と呼びます。

DIコンテナとは何だろう?

インスタンスの引数が複数となると、よりコードも複雑となります。
また、クラス同士の結合度を下げ得ることで、お互いの修正に影響しない設計とすることができます。

▼複雑化したコード例

$db = new PgSqlConnect();
$logger = new Logger();
$auth = new UserAuthenticator();
$model = new UserModel($db, $logger, $auth);
$user = $model->getById(1);

そこで、DIコンテナを使用し、UserModel自体をコンテナに登録することで、
引数の受け渡しがなくなりすっきりとしたコードにすることができます。

class Settings
{
	protected $container;

	public function __construct()
	{
		$container = new Container();
		$container['db'] = function ($c) {
			return new PgSqlConnect();
		};
	  ・・・
		$this->container = $container;
	}

	public function get($name)
	{
		return $this->container[$name];
	}
}

class UserController extends Controller
{
	public function index()
	{
		$settings = new Settings();
		$model = $settings->get('user');
		$user = $model->getById(1);
		...
	}
	...
}

Settingsでインスタンスの生成を行い、UserControllerからはSettingsのインスタンス生成を行うだけで、
UserModelの関数を実行することができ、変更に強い構成とすることができました。

さいごに

丁寧な解説とコード例でより理解することができました。

このほかにも、アンチパターンや利用時の注意点など、
DIパターンを取り入れる時に気をつけておきたいポイントも学ぶことができて、
とても充実した勉強会となりました!

今後も社内勉強会の様子を発信していきたいと思います!