[BEAR.Sunday] モジュールの仕組みを学ぶ
はじめに
仕事でモジュールの構成について学習したので記事を残すことにしました。この記事では Ray.Di で束縛を追加するとコンテナに依存情報が追加されること、モジュールの "install" や "override" でコンテナの依存情報がマージされることをFWの内部的な構成要素のレベルで確認し、モジュールが自分自身を構成する仕組みを理解する足がかりにできればと思います。
前提知識:Ray.Di における束縛の追加とは?
BEARユーザーにとって非常に馴染みが深い「束縛の追加」ですが、
protected function configure()
{
$this->bind(BarInterface::class)->to(Bar::class);
}
これが内部的にどのような構成要素から成っているかをご存知でしょうか?コードリーディングして簡略図を書きました。
束縛を追加すると Ray.Di コンテナが持つ依存情報の配列に要素が追加されます。
コンテナが持つ依存情報配列がオブジェクトグラフの元データであるという点が以降の説明の前提となる知識です。
アプリケーションのモジュールの構成
コンテナはモジュールで作られたインジェクターの操作により使われます。簡略図を示します。
Ray.Di と BEAR.Package それぞれがやっていることと境界を理解しておくことは重要ですね。
モジュールの install とは?
馴染み深いモジュール "install" の実体を確認していきます。
protected function configure()
{
$this->install(new Baz());
}
AbstractModule のスニペットを貼ります。
public function install(self $module): void
{
$this->getContainer()->merge($module->getContainer());
}
インストールしようとしているモジュール自分自身が持っているコンテナ(依存情報の配列)を、インストールより前に構成されたコンテナにマージしています。
モジュールの override とは?
「オーバーライド = 上書き」というイメージが強いかもしれませんが公式マニュアルの説明は少し異なります。
同一の束縛があれば先にされた方が優先されますが override でインストールすると後からのモジュールが優先されインストールされます。
モジュールを install したときと単にマージの順番が入れ替わっているだけで結果として上書きになっている、というイメージの方が正確なのです。
public function override(self $module): void
{
// 記事執筆者コメント: "install"と単にマージの順番($this と $module)が逆になっているだけ
$module->getContainer()->merge($this->getContainer());
$this->container = $module->getContainer();
}
モジュールごとの束縛をデバッグする方法
たとえば「アプリケーション開発でAppモジュールで束縛した FooInterface が Prod モジュールで上書きされていることをちょっとデバッグで確認したい」というようなことがあると思います。それぞれテストを書く方法をはじめいくつかやり方がありそうですが、 BEAR.Package の Module クラス に対してデバッグポイントを張りコンテナクラスが持つ container プロパティにどの依存が確定されたのかをチェックするというのは一案かと思いました。(実務だと依存数は数千あるのでコードを細工して目的の依存を取り出すひと工夫は要ります。)
終わりに
Prodモジュールのようなアプリケーションのコンテキストモジュールの configure メソッド内に直接束縛定義を書いたときと、Prodモジュールがインストールする個別のモジュールの内部で束縛定義したときとで違う構成情報になるケースがあります。個々のモジュールが構成するのは自分自身だけだという点の理解が重要です。そのあたり試行錯誤したのでそのテーマについても書きたかったのですが、今日の記事では基礎知識の導入にとどまりました。機会があれば本題の方も理解してまとめられたらと思います。
Discussion