S2ContainerApplicationContext リファレンス ( 1.2 系 )
クラスのインポート
クラスのインポートは次のメソッドで行います。
S2ContainerApplicationContext::import($path, $subDir = 0, $pear = false)
- 第1引数 : ディレクトリパス
- 第2引数 : サブディレクトリ検索を行う回数を指定
- 第3引数 : PEAR パッケージ形式のクラスファイルかどうかを指定
第1引数で指定したディレクトリにあるクラスファイル( .php、.class.php など)、ダイコンファイル( .dicon )をインポートします。インポートではクラス名とクラスファイルのパスを取得します。この情報は autoload 関数でクラス定義が require される際に使用されます。クラス名はクラスファイル名の拡張子を除く部分になります。 クラスファイル名が S2Container.php や S2Container.class.php の場合、「 S2Container 」がクラス名になります。 第2引数に -1 を指定すると無制限にサブディレクトリ検索を行います。第3引数を true と設定した場合、サブディレクトリを検索しPEAR パッケージ形式のクラスファイルとしてインポートします。
S2Container の生成
S2Container インスタンスの生成は次のメソッドで行います。
S2ContainerApplicationContext::create()
生成される S2Container は、import メソッドでインポートされた全クラスをコンポーネントとして持ちます。 import メソッドが実行されていない場合は、コンポーネントを持たない空の S2Container インスタンスが戻ります。 import メソッドで取得されたダイコンファイルについては、そのダイコンファイルを用いて S2Container を生成し、 子コンテナとして include します。
コンポーネントの選択
create メソッドで S2Container を生成する際に、インポートされたクラスやダイコンファイルから一部を選択することができます。
- default (パターン設定無し) : インポートされた全てのクラスをコンポーネントとして扱い、全てのダイコンファイルを子コンテナとして include します。
- Include Pattern : インポートされたクラスファイルとダイコンファイルに対してパターンにマッチ( preg_match )するもののみを使用します。
- Exclude Pattern : インポートされたクラスファイルとダイコンファイルに対してパターンにマッチ( preg_match )するものは除外します。
- Include & Exclude : Include Pattern と Exclude Pattern が両方設定されている場合は、Include Pattern にマッチしたものから Exclude Pattern にマッチしたものが除外されます。
setIncludePattern メソッド
S2ContainerApplicationContext::setIncludePattern($pattern = array())
- 第1引数 : 正規表現文字列、またはその配列
引数の正規表現は preg_match 関数で使用されます。クラス名が「 Bean 」で終わっているクラスを含めたい場合は、引数値は「 /Bean$/ 」となります。
setIncludePattern メソッドは、現在設定されている Include Pattern を上書きします。
addIncludePattern メソッド
S2ContainerApplicationContext::addIncludePattern($pattern)
- 第1引数 : 正規表現文字列
addIncludePattern メソッドは、現在設定されている Include Pattern にパターンを追加します。
setExcludePattern メソッド
S2ContainerApplicationContext::setExcludePattern($pattern)
- 第1引数 : 正規表現文字列、またはその配列
引数の正規表現は preg_match 関数で使用されます。クラス名が「 Abstract 」を含むクラスを除外する場合は、引数値は「 /Abstract/ 」となります。
setExcludePattern メソッドは、現在設定されている Exclude Pattern を上書きします。
addExcludePattern メソッド
S2ContainerApplicationContext::addEcludePattern($pattern)
- 第1引数 : 正規表現文字列
addExcludePattern メソッドは、現在設定されている Exclude Pattern にパターンを追加します。
ENV Filter
環境設定によりインクルードするコンポーネントを選択します。この機能はデフォルトで有効化されています。この機能を無効化する場合は、次のメソッドで設定できます。
S2ContainerApplicationContext::setFilterByEnv($val = true)
- 第1引数 : bool 値
例として、S2CONTAINER_PHP5_ENV 定数が "mock" と定義されている場合、インポートされたクラスに、Hoge クラスと MockHoge クラスが存在すると、MockHoge クラスのみ選択します。
自動アスペクト
コンポーネントの選択でインクルードされたコンポーネントに対して、自動的にアスペクトを適用します。
S2ContainerApplicationContext::registerAspect($componentPattern, $interceptor, $pointcut = null)
- 第1引数 : コンポーネント名またはコンポーネントクラス名にパターンマッチする正規表現文字列
- 第2引数 : Interceptorコンポーネント名、または Expression
- 第3引数 : ポイントカットをカンマ区切りで指定
コンポーネントクラス名が「Dao」で終わっているコンポーネントに、dao.interceptorをアスペクトしたい場合は、次のように設定します。
S2ContainerApplicationContext::registerAspect('/Dao$/', 'dao.interceptor');
自動アスペクトはコンポーネントに対してのみ適用されます。インクルードされたダイコンファイルに含まれるコンポーネントには適用されません。
アノテーション
コンポーネントの細かい設定や、Dependency Injection 設定、Aspect の適用を行う場合はアノテーションを用います。 アノテーションの形式は、@アノテーション名[()] です。アットマーク(@)で開始します。末尾はスペース、または改行となります。 アノテーションでは引数を記述することができます。引数の形式は、PHP 配列と同じフォーマットです。
親クラスのメソッドアノテーション
デフォルトでは親クラスのメソッドアノテーションは無効となります。親クラスのメソッドアノテーションを有効とする場合は、次のメソッドで設定できます。
S2ContainerApplicationContext::setReadParentAnnotation($val = true)
- 第1引数 : bool 値、trueを設定すると親クラスのメソッドアノテーションが有効となります。
@S2Component アノテーション
コンポーネント情報を設定します。
- アノテーションの表記 : @S2Component
- 引数
- name : コンポーネント名
- instance : インスタンスモードタイプ
- autoBinding : バインディングモードタイプ
- available : コンポーネントとして使用するかどうか (boolean default true)
- 注釈ポイント : クラス
- サンプル
/** * @S2Component('name' => 'hoge') */ /** * @S2Component('name' => 'hoge', 'instance' => 'singleton', 'autoBinding' => 'auto', 'available' => true) */
@S2Binding アノテーション
手動インジェクション設定を行います。
- アノテーションの表記 : @S2Binding
- 引数 : インジェクションするコンポーネント名、または Expression
- 注釈ポイント : セッターメソッド
- サンプル
/** * @S2Binding('hoge') */ public function setHoge($hoge) { $this->hoge = $hoge; } /** * @S2Binding('Hello World') */ public funcion setHello($val) { $this->hello = $val; }
@S2Aspect アノテーション
アスペクト情報を設定します。
- アノテーションの表記 : @S2Aspect
- 引数
- interceptor : Interceptorコンポーネント名、または Expression
- pointcut : ポイントカットをカンマ区切りで指定
- 注釈ポイント : クラス、メソッド
- サンプル
/** * @S2Aspect('interceptor' => 'traceInterceptor', * 'pointcut' => '.+Action') */ class CdController { public function indexAction(){ ・・・ } } class DvdController { /** * @S2Aspect('interceptor' => 'new S2Container_TraceInterceptor()') */ public funcion indexAction() { ・・・ } }
@S2Meta アノテーション
メタ情報を設定します。
- アノテーションの表記 : @S2Meta
- 引数
- name : メタ情報の識別名
- value : 値、または Expression
- 注釈ポイント : クラス
- サンプル
/** * @S2Meta('nameA' => 'valueA', * 'nameB' => 'valueB') */ class CdController { public function indexAction(){ ・・・ } }
S2Container リファレンス
作成すべきファイル
S2Containerを使用するためには、定義ファイルを作成する必要があります。 定義ファイルは、コンポーネントを組み立てるための設計書のようなものです。 定義ファイルの拡張子は .dicon、または .xml です。diconは「ダイコン」と読みます
S2Containerの定義
S2Containerの定義は、次のようになります。
<?xml version="1.0" encoding="Shift_JIS"?> <!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN" "http://www.seasar.org/dtd/components21.dtd"> <components> <component name="..." class="..."> ... </component> <component name="..." class="..."> ... </component> </components>
DOCTYPEは省略できません。diconファイルを作成する場合は、上記のサンプルをコピー&ペーストしてください。 ルートはcomponentsタグです。コンポーネントごとに、 componentタグを定義していきます。componentタグの class属性でコンポーネントのクラス名を指定します。name属性には、コンポーネント名を指定します。 詳細は、S2Container定義タグリファレンスを参照してください。
<components> <component name="hoge" class="HogeImpl"/> </components>
S2Containerの生成
S2Containerを作成する場合は、次のメソッドを使用します。
- S2ContainerFactory#create($path)
引数$pathは設定ファイルのパスです。
<?php $PATH = "path/to/ccc.dicon"; ... $container = S2ContainerFactory::create($PATH); ?>
コンポーネントの取得
S2Containerからコンポーネントを取り出すには、次のメソッドを使用します。
- S2Container#getComponent($componentKey)
引数には、コンポーネントのクラスもしくはコンポーネント名を指定できます。
詳しくは、componentタグを参照してください。
コンポーネントのクラスを指定する場合、コンポーネント instanceof クラスが true を返すクラスなら
指定することができます。しかし、S2Containerの中に指定したクラスを実装しているコンポーネントが複数ある
場合、S2Containerは、どのコンポーネントを返せばよいのか判断できないため、
TooManyRegistrationRuntimeExceptionが発生します。実装コンポーネントがユニークに決まるクラスを指定してくださ
い。コンポーネント名で取得することもできます。その場合も、同一の名前をもつコンポーネントが複数登録されている場合、
TooManyRegistrationRuntimeExceptionが発生します。
例) 以下のように Hoge クラスがコンポーネント名 hoge で設定されているとします。
<components> <component name="hoge" class="Hoge"/> </components>
クラスを指定してコンポーネントを取得する場合
<?php $container = S2ContainerFactory::create($PATH); $hoge = $container->getComponent('Hoge'); ?>
コンポーネント名を指定してコンポーネントを取得する場合
<?php $container = S2ContainerFactory::create($PATH); $hoge = $container->getComponent('hoge'); ?>
Dependency Injectionのタイプ
Dependency Injectionには以下のタイプがあります。
- Constructor Injection | コンポーネントの構成に必要な値をコンストラクタで設定する | ||
- Setter Injection | コンポーネントの構成に必要な値をセッター・メソッドで設定する | ||
- Method Injection | コンポーネントの構成に必要な値を初期化メソッドで設定する | ||
MethodInjectionはS2のオリジナルです。S2はすべてのタイプとそのハイブリッド型もサポートします。
コンストラクタ・インジェクション
コンストラクタ・インジェクションとは、任意のコンストラクタの引数値にDependency Injectionします。
S2Containerの定義ファイルには、次の内容を記述します。
- コンポーネントの指定
コンポーネントは、componentタグで組み立てます。class属性でクラス名を指定します。
name属性でコンポーネントに名前を付けることもできます。 - コンストラクタの引数の指定
コンポーネントのコンストラクタの引数は、 componentタグの子タグであるargタグを使って指定します。
文字列の場合は、ダブルコーテーション(")で囲みます。
<components> <component name="..." class="..."> <arg>...</arg> </component> </components>詳しい使用方法は、Exampleのコンストラクタ・インジェクションを参照してください。
セッター・インジェクション
セッター・インジェクションとは、任意のプロパティにセッターメソッドを使用してDependency Injectionします。
S2Containerの定義ファイルには、次の内容を記述します。
- コンポーネントの指定
コンポーネントの指定は、コンストラクタ・インジェクションと同様です。
name属性でコンポーネントに名前を付けることもできます。 - プロパティの指定
コンポーネントのプロパティは、componentタグの子タグであるpropertyタグを使って指定します。
name属性でプロパティ名を指定します。
<components> <component name="..." class="..."> <property name="...">...</property> </component> </components>詳しい使用方法は、Exampleのセッター・インジェクションを参照してください。
メソッド・インジェクション
メソッド・インジェクションとは、任意のメソッドを呼び出して、Dependency Injectionします。
S2Containerの定義ファイルには、次の内容を記述します。
- コンポーネントの指定
コンポーネントの指定は、コンストラクタ・インジェクションと同様です。
name属性でコンポーネントに名前を付けることもできます。 - 初期化メソッドの指定
initMethodタグを使って、コンポーネントの任意のメソッドを呼び出します。 name属性で、メソッド名を指定します。引数は、argタグを子タグに使います。 name属性を省略して、ボディで、PHP式を使うこともできます。その際、コンポーネント自身は$componentで表します。
<componets> <component name="..." class="..."> <initMethod>...</initMethod> </component> </components>詳しい使用方法は、Exampleのメソッド・インジェクションを参照してください。
S2Container定義の分割とインクルード
すべてのコンポーネントを1つのファイルに記述すると、直ぐに肥大化してしまい管理が難しくなります。 そのため、コンポーネントの定義を複数に分割する機能と分割された定義をインクルードして1つにまとめる機能が S2Containerにあります。S2Container定義ファイルのインクルードは次のようにして行います。
<components> <include path="bar.dicon"/> </components>includeタグのpath属性で取り込みたいS2Container定義ファイルのパスを指定します。 詳しくは、includeタグを参照してください。 コンポーネントの検索順は、先ず自分自身に登録されているコンポーネントを探して、見つからない場合は、 includeされている順に子供のS2Containerに登録されているコンポーネントを検索し、最初に見つかったコンポーネントが返されます。 次のような場合は、Foo(自身のコンポーネント)→aaa(子供のS2Container)→bbb(子供のS2Container)の順に検索します。
<components> <include path="aaa.dicon"/> <include path="bbb.dicon"/> <component class="Foo" /> </components>自動でコンストラクタ・インジェクションやセッター・インジェクションを行う場合、 S2Containerはインクルード先のコンポーネントを自動インジェクションすることができます。自動でDependency Injectionを行う場合の条件は 自動バインディングを参照してください。
次のようにセッター・インジェクションでプロパティに指定するコンポーネントがインクルード先のaaa.diconとbbb.diconに登録されている場合、 各HelloClientでは、どちらのコンポーネントが使用されるかをみてましょう。
■ root.dicon
<components> <include path="aaa.dicon"/> <include path="bbb.dicon"/> <component name="root" class="RootHelloClient"/> </components>■ aaa.dicon
<components> <component class="HelloImpl"> <property name="message">"Hello Aaa!"</property> </component> <component name="aaa" class="AaaHelloClient"/> </components>■ bbb.dicon
<components> <component class="HelloImpl"> <property name="message">"Hello Bbb!"</property> </component> <component name="bbb" class="BbbHelloClient"/> </components>各コンポーネントの内容は、次のようになります。
<?php interface HelloClient { public function showMessage(); } ?>
<?php class RootHelloClient implements HelloClient { private $hello_; public function setHello(Hello $hello) { $this->hello_ = $hello; } public function getHello() { return $this->hello_; } public function showMessage() { print $this->getHello()->getMessage(); } } ?>AaaHelloClientとBbbHelloClientはRootHelloClient同様の実装です。
<?php interface Hello { public function setMessage($helloMessage); public function getMessage(); } ?>
<?php class HelloImpl implements Hello { private $helloMessage_; public function setMessage($helloMessage) { $this->helloMessage_ = $helloMessage; } public function getMessage() { return $this->helloMessage_; } } ?>HelloImplはMessageプロパティを定義しているだけです。各HelloClientのshowMessage()を呼び出した 場合の実行結果は次のようになります。
■ RootHelloClientの実行結果
Hello Aaa!まず、S2Containerはroot.diconにHelloImplが登録されているかを検索します。 root.diconにはないので、次にインクルード先のaaa.diconを検索します。aaa.diconにはHelloImplが登録されているので、 そのコンポーネントを使用します。
■ AaaHelloClientの実行結果
Hello Aaa!AaaHelloClientは、aaa.diconに登録されているコンポーネントを使用します。自動でインジェクションを行う場合、 子供のS2Containerは親のS2Containerのコンポーネントを使用することはできません。 例えば、root.diconにHelloImplを登録していてもAaaHelloClientには自動インジェクションされないということです。
■ BbbHelloClientの実行結果
Hello Bbb!AaaHelloClientと同様にBbbHelloClientもbbb.diconに登録されているコンポーネントを使用します。 このサンプルは、s2container.php5/examples/dicon/include以下に用意されています。
名前空間
コンポーネントの定義を分割した場合に、複数のコンポーネント定義間で名前が衝突しないように、 componentsタグのnamespace属性で名前空間を指定することができます。
■ foo.dicon<components namespace="foo"> <component name="aaa" .../> <component name="bbb" ...> <arg>aaa</arg> </component> </components>■ bar.dicon
<components namespace="bar"> <include path="foo.dicon"/> <component name="aaa" .../> <component name="bbb" ...> <arg>aaa</arg> </component> <component name="ccc" ...> <arg>foo.aaa</arg> </component> </components>■ app.dicon
<components> <include path="bar.dicon"/> </components>同一のコンポーネント定義内では、名前空間なしで参照できます。他のS2Container定義のコンポーネントを参照する場合は、 名前空間.をコンポーネント名の頭につけます。foo.aaaとbar.aaaは同じ名前がついていますが、 名前空間が異なっているので、違うコンポーネントとして認識されます。慣習として、定義ファイルの名前は、 名前空間.diconにすることを推奨します。
インスタンス管理
S2Containerで、コンポーネントのインスタンスをどのように管理するのかを指定するのが、 componentタグのinstance属性です。デフォルトはsingletonで、 これは S2Container#getComponent()によって返されるコンポーネントは常に同じだという意味です。 S2Container#getComponent()を呼び出すたびに、新たに作成されたコンポーネントを返して欲しい場合は、 instance属性にprototypeを指定します。リクエスト($_REQUEST)ごとにコンポーネントを管理したい場合は、 instance属性にrequestを指定します。セッション($_SESSION)ごとにコンポーネントを管理したい場合は、 instance属性にsessionを指定します。
プレゼンテーションのフレームワークと組み合わせるときに、プレゼンテーションフレームワークが作成した
インスタンスに対して、S2Containerで管理されているコンポーネントをセットしたい場合があります。
そのようなS2Container外のコンポーネントに対してDependency Injectionしたいときには、
次のメソッドを使用します。
- S2Container#injectDependency($outerComponent, $componentKey)
第一引数には、外部のコンポーネントを指定します。第二引数には、外部コンポーネントのクラス、
またはコンポーネント名を指定します。そのとき、S2Container定義では、instance属性にouterを指定します。
instance属性 | 説明 |
---|---|
singleton(default) | S2Container#getComponent()を何度呼び出しても同じインスタンスが返されます。 |
prototype | S2Container#getComponent()を呼び出すたびに新たなインスタンスが返されます。 |
request | リクエスト毎に1つのインスタンスが作成されます。name属性に指定した名前で、 コンポーネントがリクエストに格納されます。 |
session | セッション毎に1つのインスタンスが作成されます。name属性に指定した名前で、 コンポーネントがセッションに格納されます。 |
outer | コンポーネントのインスタンスは、S2Container外で作成し、Dependency Injectionだけを行います。アスペクト、コンストラクタ・インジェクションは適用できません。 |
ライフサイクル
initMethodやdestroyMethodでコンポーネントのライフサイクルもコンテナで管理することができます。 S2Containerの開始時(S2Container#init())にinitMethodタグで指定したメソッドが呼び出され、 S2Containerの終了時(S2Container#destroy())にdestroyMethodタグで指定したメソッドが呼び出されるようになります。 initMethodはコンポーネントがコンテナに登録した順番に実行され、destroyMethodはその逆順に呼び出されることになります。 instance属性がsingleton以外の場合、destroyMethodを指定しても無視されます。HashMap#put()メソッドに 初期化(aaaに111を設定)・終了処理(aaaにnullを設定)を設定する場合は、次のようになります。
<components namespace="bar"> <component name="map" class="HashMap"> <initMethod name="put"> <arg>"aaa"</arg> <arg>111</arg> </initMethod> <destroyMethod name="put"> <arg>"aaa"</arg> <arg>null</arg> </destroyMethod> </component> </components>
自動バインディング
コンポーネント間の依存関係は、型がインターフェースの場合、コンテナによって自動的に解決されます。 これがS2Containerのデフォルトですが、componentタグのautoBinding属性を指定することで細かく制御することもできます。
autoBinding | 説明 |
---|---|
auto(default) |
コンストラクタの引数が明示的に指定されている場合は、それに従います。 指定されていない場合、型がインターフェースの場合は自動的にバインドします。 型がインタフェースでない引数にはdefault値を使用します。default値が取得できない場合はnull値を使用します。 プロパティが明示的に指定されている場合はそれに従います。 明示的に指定されていないプロパティで、型がインターフェースの場合は自動的にバインドします。 |
constructor |
コンストラクタの引数が明示的に指定されている場合は、それに従います。 指定されていない場合、型がインターフェースの場合は自動的にバインドします。 型がインタフェースでない引数にはdefault値を使用します。default値が取得できない場合はnull値を使用します。 プロパティが明示的に指定されている場合は、それに従います。 |
property | コンストラクタの引数が明示的に指定されている場合は、それに従います。 型がインターフェースのプロパティを自動的にバインドします。 |
none | コンストラクタの引数が明示的に指定されている場合は、それに従います。 プロパティが明示的に指定されている場合はそれに従います。 |
詳しくは、自動バインディング(コンストラクタ・インジェクション)と 自動バインディング(セッター・インジェクション)を参照してください。
コンポーネントでS2Containerを利用する
コンポーネントはS2Containerに依存しないことが望ましいのですが、コンポーネントによっては、 S2Containerのメソッドを呼び出したい場合もあるでしょう。S2Container自身もcontainerという名前で登録されているので、 arg、propertyタグのボディでcontainerを指定することで、コンテナのインスタンスを取得できます。 また、S2Container型のsetterメソッドを定義しておいて自動バインディングで設定することもできます。 arg、propertyタグでcontainerを指定する場合は、次のようになります。
<components> <component class="BarImpl"> <arg>container</arg> </component> <component class="FooImpl"> <property name="foo">container</property> </component> </components>
AOPの適用
コンポーネントにAOPを適用することもできます。例えば、DateクラスにTraceInterceptorを 適用したい場合次のようにします。
<?php class Date { function Date() {} function getTime(){ return '12:00:30'; } } ?>
<components> <component name="traceInterceptor" class="S2Container_TraceInterceptor"/> <component class="Date"> <aspect>traceInterceptor</aspect> </component> </components>
aspectタグのボディでInterceptorの名前を指定します。 pointcut属性にカンマ区切りで対象となるメソッド名を指定することができます。pointcut属性を指定しない場合は、 コンポーネントが実装しているインターフェースのすべてのメソッドが対象になります。 メソッド名には正規表現も使えます。この定義を使うサンプルは次のようになります。
<?php $PATH ="Aop.dicon"; $container = S2ContainerFactory::create($PATH); $date = $container->getComponent('Date'); $date->getTime(); ?>実行結果は次のようになります。
BEGIN Date#getTime() END Date#getTime() : 12:00:30
メタデータ
components、component、arg、propertyタグにメタデータを指定することもできます。 metaタグはメタデータを指定したいタグの子タグに指定します。例えば、componentsタグにメタデータを指定したい場合次のようにします。
<components> <meta name="aaa">111</meta> </components>
components、component、arg、propertyタグに指定したメタデータの情報は、S2Container、ComponentDef、ArgDef、 PropertyDefで定義されている次のメソッドで取得することが出来ます。
- public function getMetaDefSize()
- public function getMetaDef($name)
S2Container定義タグリファレンス
DOCTYPE
DOCTYPEは、XML宣言の次に指定します。下記のように指定してください。
<?xml version="1.0" encoding="Shift_JIS"?> <!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN" "http://www.seasar.org/dtd/components21.dtd"> <components> <component name="hello" class="HelloConstructorInjection"> <arg>"Hello World!"</arg> </component> </components>
componentsタグ(必須)
ルートのタグになります。
namespace属性(任意)
名前空間を指定することができます。PHPの識別子として使えるものにします。
<?xml version="1.0" encoding="Shift_JIS"?> <!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN" "http://www.seasar.org/dtd/components21.dtd"> <components namespace="hoge"> ... </components>
includeタグ(任意)
分割されたS2Containerの定義を取り込む場合に使います。
path属性(必須)
定義ファイルのパスを指定することができます。componentタグの前に記述する必要があります。 定義ファイルへのパスは絶対パスになります。パスの先頭に%・・・%で囲む事で PHP で定義した定数を指定できます。
<?xml version="1.0" encoding="Shift_JIS"?> <!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN" "http://www.seasar.org/dtd/components21.dtd"> <components> <include path="path/to/ccc.dicon" /> <include path="%DICON_DIR%/ddd.dicon" /> </components>
componentタグ(任意)
コンポーネントを定義します。
class属性(任意)
クラス名を指定します。ボディでPHP式を使ってコンポーネントを指定した場合は、class属性を省略することができます。PHP式を使った場合にclass属性を指定すると、型チェックを行います。
name属性(任意)
名前を指定することもできます。PHPの識別子として使えるものにします。詳しくは、コンポーネントの取得を参照してください。
instance属性(任意)
S2Containerがどのようにコンポーネントのインスタンスを管理するのかを指定することができます。singleton(デフォルト)、prototype、outer、request、sessionを指定することができます。詳しくはインスタンス管理を参照してください。
autoBinding属性(任意)
S2Containerがコンポーネントの依存関係をどのように解決するのかを指定できます。auto(デフォルト)、constructor、property、noneを指定することができます。詳しくは、自動バインディングを参照してください。
argタグ(任意)
componentタグの子タグとして使った場合は、コンストラクタの引数になります。記述した順番でコンストラクタに渡されます。 initMethodタグ、destroyMethodタグの子タグとして使った場合は、メソッドの引数になります。記述した順番でメソッドに渡されます。 引数として渡される実際の値は、ボディでPHP式を使うか、子タグでcomponentタグを使います。
propertyタグ(任意)
componentタグの子タグとして使います。プロパティとして設定される実際の値は、ボディでPHP式を使うか、子タグでcomponentタグを使います。
name属性(必須)
プロパティ名を指定します。
metaタグ(任意)
componentsタグ、componentタグ、argタグ、propertyタグの子タグとして使います。メタデータの値は、ボディでPHPを使うか、子タグでcomponentタグを使います。
name属性(任意)
メタ名を指定します。
initMethodタグ(任意)
componentタグの子タグとして使います。引数は、子タグでargタグを使います。name属性を書かずにPHP式を使って、コンポーネントのメソッドを呼び出すこともできます。initMethodタグが定義されているコンポーネント自身を表す$componentがinitMethodタグ内だけで有効なオブジェクトとして使えます。
name属性(任意)
メソッド名を指定します。
<?xml version="1.0" encoding="Shift_JIS"?> <!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN" "http://www.seasar.org/dtd/components21.dtd"> <components> <component class="HashMap"> <initMethod name="put"> <arg>"aaa"</arg> <arg>111</arg> </initMethod> <initMethod>$component->put("aaa", 111);</initMethod> <initMethod>print "Hello";</initMethod> </component> </components>
destroyMethodタグ(任意)
initMethodタグと同様です。
aspectタグ(任意)
アスペクトをコンポーネントに組み込みます。詳しくは、aspectタグの説明を参照してください。
interTypeタグ(任意)
インタータイプをコンポーネントに組み込みます。詳しくは、S2AOPのinterTypeタグの説明を参照してください。
descriptionタグ(任意)
componentsタグ、componentタグ、argタグ、propertyタグの子タグとしてdescriptionタグを使うことができます。自由に説明を記述できます。
S2Containerで使用される定数
S2CONTAINER_PHP5_DOM_VALIDATE
ダイコンファイルを読み込む際に、DTD検証を実施するかどうかをbool値で指定します。
- デフォルト値 : true
S2CONTAINER_PHP5_APP_DICON
S2Container_SingletonS2ContainerFactorが使用するダイコンファイル指定します。
- デフォルト値 : 未定義
S2CONTAINER_PHP5_LOG_LEVEL
S2Container.PHP5のログレベルを定義します。S2Container.PHP5 の S2Container_SimpleLoggerクラスのログレベルには、DEBUG、INFO、WARN、ERROR、FATAL があります。
- デフォルト値 : S2Container_SimpleLogger::WARN
S2CONTAINER_PHP5_DEBUG_EVAL
S2Container.PHP5のログレベルが DEBUG の場合に、eval関数で実行されるスクリプトを出力するかどうかをbool値で指定します。
- デフォルト値 : false
S2CONTAINER_PHP5_SIMPLE_LOG_FILE
S2Container_SimpleLoggerのログ出力先ファイルを指定します。
- デフォルト値 : 未定義 (stdout)
S2CONTAINER_PHP5_ANNOTATION_HANDLER
アノテーションタイプをクラス名で指定します。(S2Container_ConstantAnnotationHandler または S2Container_CommentAnnotationHandler)
- デフォルト値 : S2Container_ConstantAnnotationHandler
S2CONTAINER_PHP5_ENV
環境指定を行います。この値は、ダイコンファイルを読み込む際に、ダイコンファイルのSuffixとして使用されます。
S2CONTAINER_PHP5_ENV が test と定義されていて、foo.dicon と foo_test.diconが存在した場合、foo_test.diconが
使用されます。
- デフォルト値 : 未定義
S2CONTAINER_PHP5_AUTO_DI_INTERFACE ( version 1.2 以降 )
自動インジェクションにおいて、インターフェイスでタイプヒンティングされている場合にのみDIを許可するかどうかを bool値 で指定します。
- デフォルト値 : 未定義 (false)
Example
以下のサンプルを実行する場合は、セットアップを行う必要があります。
コンストラクタ・インジェクション
コンストラクタ・インジェクションを使ってメッセージを表示しましょう。作成するファイルは以下のとおりです。
- インターフェース(Hello.class.php)
- 実装クラス(HelloConstructorInjection.class.php)
- diconファイル(HelloConstructorInjection.dicon)
- 実行スクリプト(HelloConstructorInjectionClient.php)
インターフェースの作成
- showMessage()を定義します。
先ず最初はインターフェースを考えます。インターフェースと実装を分離することで、コンポーネントの利用者は、 インターフェースを知っていれば実装のことは知らなくても済むようになります。 また、テストの時には実装をモックに置き換えることで簡単にテストできるようになります。
<?php interface Hello { public function showMessage(); } ?>
実装クラスの作成
- 引数が1つのンストラクタを定義します。
- showMessage()を実装します。
次はいよいよ実装です。コンストラクタでメッセージを受け取り、showMessage()で受け取ったメッセージを出力します。
<?php class HelloConstructorInjection implements Hello { private $message; public function HelloConstructorInjection($message) { $this->message = $message; } public void showMessage() { print $this->message . "\n"; } } ?>
diconファイルの作成
- componentタグでコンポーネントを定義します。
- componentタグの子タグのargタグでコンストラクタの引数値を定義します。
メッセージをコンポーネントに設定するのは、S2Containerの仕事です。定義ファイルに基づいてコンポーネントを組み立てます。
s2container.php5/examples/dicon/injection/HelloConstructorInjection.dicon
<?xml version="1.0" encoding="Shift_JIS"?> <!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN" "http://www.seasar.org/dtd/components21.dtd"> <components> <component name="hello" class="HelloConstructorInjection"> <arg>"Hello World!"</arg> </component> </components>
実行スクリプトの作成
- S2ContainerFactory#create($path)を呼び出してS2Containerを作成します。
- getComponent()を使用して、S2Containerからコンポーネントを取り出します。
- 取得したコンポーネントのメソッドを呼び出します。
s2container.php5/examples/dicon/injection/HelloConstructorInjectionClient.php
<?php require_once(dirname(dirname(dirname(__FILE__))) . '/example.inc.php'); require_once('Hello.class.php'); require_once('HelloConstructorInjection.class.php'); $PATH = EXAMPLE_DIR . "/dicon/injection/HelloConstructorInjection.dicon"; $container = S2ContainerFactory::create($PATH); $hello = $container->getComponent('Hello'); $hello->showMessage(); $hello2 = $container->getComponent("hello"); $hello2->showMessage(); ?>
実行結果
argタグで指定した文字列が正しく表示されていることが確認できます。
% php HelloConstructorInjectionClient.php Hello World! Hello World! %
この演習は、s2container.php5/examples/dicon/injection以下に用意されています。
セッター・インジェクション
セッター・インジェクションを使ってメッセージを表示しましょう。作成するファイルは以下のとおりです。
- インターフェース(Hello.class.php)
- 実装クラス(HelloSetterInjection.class.php)
- diconファイル(HelloSetterInjection.dicon)
- 実行スクリプト(HelloSetterInjectionClient.php)
インターフェースの作成
- showMessage()を定義します。
インターフェースはコンストラクタ・インジェクションの場合と同じです。プロパティに対するゲッター・メソッド、 セッター・メソッドを定義する必要はありません。なぜなら、Dependency Injectionするのにコンストラクタを使うのか セッター・メソッドを使うのかは実装の問題だからです。
<?php interface Hello { public void showMessage(); } ?>
実装クラスの作成
- セッター・メソッド(setMessage)を定義します。
- showMessage()を実装します。
次は実装です。セッター・メソッドでメッセージを受け取り、showMessage()で受け取ったメッセージを出力します。
<?php class HelloSetterInjection implements Hello { private $message; public function HelloSetterInjection() { } public function setMessage($message) { $this->message = $message; } public function showMessage() { print $this->message . "\n"; } } ?>
diconファイルの作成
- componentタグでコンポーネントを定義します。
- componentタグの子タグのpropertyタグでコンポーネントのプロパティ値を定義します。
s2container.php5/examples/dicon/injection/HelloSetterInjection.dicon
<?xml version="1.0" encoding="Shift_JIS"?> <!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN" "http://www.seasar.org/dtd/components21.dtd"> <components> <component class="HelloSetterInjection"> <property name="message">"Hello World!"</property> </component> </components>
実行スクリプトの作成
- S2ContainerFactory#create($path)を呼び出してS2Containerを作成します。
- getComponent()を使用して、S2Containerからコンポーネントを取り出します。
- 取得したコンポーネントのメソッドを呼び出します。
s2container.php5/examples/dicon/injection/HelloSetterInjectionClient.php
<?php require_once(dirname(dirname(dirname(__FILE__))) . '/example.inc.php'); require_once('Hello.class.php'); require_once('HelloSetterInjection.class.php'); $PATH = EXAMPLE_DIR . "/dicon/injection/HelloSetterInjection.dicon"; $container = S2ContainerFactory::create($PATH); $hello = $container->getComponent('Hello'); $hello->showMessage(); ?>
実行結果
propertyタグで指定した文字列が正しく表示されていることが確認できます。
% php HelloSetterInjectionClient.php Hello World! %
この演習は、s2container.php5/examples/dicon/injection以下に用意されています。
メソッド・インジェクション
メソッド・インジェクションを使ってメッセージを表示しましょう。作成するファイルは以下のとおりです。
- インターフェース(Hello.class.php)
- 実装クラス(HelloMethodInjection.class.php)
- diconファイル(HelloMethodInjection.dicon)
- 実行スクリプト(HelloMethodInjectionClient.php)
インターフェースの作成
- showMessage()を定義します。
追加のメソッドを複数回呼び出すようなケースが代表的な使い方ですが、今回の演習では、インターフェースはコンストラクタ・インジェクションの場合と同じにしました。
<?php interface Hello { public function showMessage(); } ?>
実装クラスの作成
- addMessage()を定義します。
- showMessage()を実装します。
次は実装です。addMessage($message)でメッセージを複数回追加して、showMessage()で受け取ったメッセージを出力します。
<?php class HelloMethodInjection implements Hello { private $buf = ""; public function HelloMethodInjection() {} public function addMessage($message) { $this->buf .= $message; } public function showMessage() { print $this->buf . "\n"; } } ?>
diconファイルの作成
- componentタグでコンポーネントを定義します。
- componentタグの子タグのinitMethodタグでコンポーネントのメソッドの引数値を定義します。
先ずは、argタグを使ってaddMessage($message)に"Hello "を指定します。
次にPHP式を使ってaddMessage($message)に"World!"を指定します。
s2container.php5/examples/dicon/injection/HelloMethodInjection.dicon
<?xml version="1.0" encoding="Shift_JIS"?> <!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN" "http://www.seasar.org/dtd/components21.dtd"> <components> <component class="HelloMethodInjection"> <initMethod name="addMessage"> <arg>"Hello "</arg> </initMethod> <initMethod>$component->addMessage("World!")</initMethod> </component> </components>
実行スクリプトの作成
- S2ContainerFactory#create($path)を呼び出してS2Containerを作成します。
- getComponent()を使用して、S2Containerからコンポーネントを取り出します。
- 取得したコンポーネントのメソッドを呼び出します。
<?php require_once(dirname(dirname(dirname(__FILE__))) . '/example.inc.php'); require_once('Hello.class.php'); require_once('HelloMethodInjection.class.php'); $PATH = EXAMPLE_DIR . "/dicon/injection/HelloMethodInjection.dicon"; $container = S2ContainerFactory::create($PATH); $hello = $container->getComponent('Hello'); $hello->showMessage(); ?>
実行結果
initMethodタグで指定した文字列が正しく表示されていることが確認できます。
% php HelloMethodInjectionClient.php Hello World! %
この演習は、s2container.php5/examples/dicon/injection/以下に用意されています。
自動バインディング(コンストラクタ・インジェクション)
自動バインディングでメッセージを表示してみましょう。作成するファイルは以下のとおりです。
- インターフェース(Hello.class.php)
- インターフェースの実装クラス(AutoHelloConstructorInjection.class.php)
- Mapインターフェース(Map.class.php)
- Mapインターフェースの実装クラス(HashMap.class.php)
- diconファイル(AutoHelloConstructorInjection.dicon)
- 実行スクリプト(AutoHelloConstructorInjectionClient.php)
インターフェースの作成
- showMessage()を定義します。
<?php interface Hello { public function showMessage(); } ?>
実装クラスの作成
- 引数がMapのコンストラクタを定義します。
- showMessage()を実装します。
コンストラクタでMapを受け取り、showMessage()でhelloをキーとしてMapから値を取得して出力します。
<?php class AutoHelloConstructorInjection implements Hello { private $messages; public function AutoHelloConstructorInjection(Map $messages) { $this->messages = $messages; } public function showMessage() { print $this->messages->get('hello') . "\n"; } } ?>
Mapインターフェースの作成
- put($key,$val)を定義します。
- get($key)を定義します。
<?php interface Map { function put($key,$val); function get($key); } ?>
Mapインターフェースの実装クラスの作成
- 引数がMapのコンストラクタを定義します。
- showMessage()を実装します。
<?php class HashMap implements Map{ private $pool = array(); function HashMap() {} function put($key,$val){ $this->pool[$key] = $val; } function get($key){ return array_key_exists($key,$this->pool) ? $this->pool[$key] : null; } } ?>
diconファイルの作成
- componentタグでMapの実装クラスであるHashMapをコンポーネント定義します。
- componentタグの子タグであるinitMethodタグでHashMapにキーとして"hello"、値として"Hello World!"を定義します。
- componentタグでAutoHelloConstructorInjectionをコンポーネント定義します。autoBinding属性にautoを指定します。演習であるため auto を明示的に指定していますが、autoBinding属性のデフォルト値であるため本来は省略します。
AutoHelloConstructorInjectionには、argタグが定義されていないことに注目してください。コンストラクタ・インジェクションを行う場合、
argタグを定義する必要がありますが、S2Container内にMapの実装クラスが登録されていれば、S2Containerがコンテナ内を検索して
自動的に引数を設定します。ただし、引数の型がインターフェースでない場合、自動バインディングはできません。
s2container.php5/examples/dicon/autobinding/AutoHelloConstructorInjection.dicon
<?xml version="1.0" encoding="Shift_JIS"?> <!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN" "http://www.seasar.org/dtd/components21.dtd"> <components> <component class="HashMap"> <initMethod name="put"> <arg>"hello"</arg> <arg>"Hello World!"</arg> </initMethod> </component> <component autoBinding="auto" class="AutoHelloConstructorInjection"/> </components>
実行スクリプトの作成
- S2ContainerFactory#create($path)を呼び出してS2Containerを作成します。
- getComponent()を使用して、S2Containerからコンポーネントを取り出します。
- 取得したコンポーネントのメソッドを呼び出します。
<?php require_once(dirname(dirname(dirname(__FILE__))) . '/example.inc.php'); require_once('Hello.class.php'); require_once('Map.class.php'); require_once('HashMap.class.php'); require_once('AutoHelloConstructorInjection.class.php'); $PATH = EXAMPLE_DIR . "/dicon/autobinding/AutoHelloConstructorInjection.dicon"; $container = S2ContainerFactory::create($PATH); $hello = $container->getComponent('Hello'); $hello->showMessage(); ?>
実行結果
HashMapの値が表示されていることから、自動的にコンストラクタの引数を設定していることが確認できます。
% php AutoHelloConstructorInjection.php Hello World! %
この演習は、s2container.php5/examples/dicon/autobinding以下に用意されています。
自動バインディング(セッター・インジェクション)
自動バインディングでメッセージを表示してみましょう。作成するファイルは以下のとおりです。
- インターフェース(Hello.class.php)
- インターフェースの実装クラス(AutoHelloSetterInjection.class.php)
- diconファイル(AutoHelloSetterInjection.dicon)
- 実行スクリプト(AutoHelloSetterInjectionClient.php)
インターフェースの作成
- showMessage()を定義します。
<?php interface Hello { public function showMessage(); } ?>
実装クラスの作成
- 引数がMapのshowMessage()を実装します。
setMessage(Map map)でMapを受け取り、showMessage()でhelloをキーとしてMapから値を取得して出力します。
<?php class AutoHelloSetterInjection implements Hello { private $messages; public function AutoHelloSetterInjection() {} public function setMessage(Map $messages) { $this->messages = $messages; } public function showMessage() { print $this->messages->get('hello') . "\n"; } } ?>
diconファイルの作成
- componentタグでMapの実装クラスであるHashMapをコンポーネント定義します。
- componentタグの子タグであるinitMethodタグでHashMapにキーとして"hello"、値として"Hello World!"を定義します。
- componentタグでAutoHelloSetterInjectionをコンポーネント定義します。autoBinding属性にautoを指定します。
演習であるため auto を明示的に指定していますが、autoBinding属性のデフォルト値であるため本来は省略します。
AutoHelloSetterInjectionには、propertyタグが定義されていないことに注目してください。セッター・インジェクションを行う場合、
propertyタグで任意のプロパティを定義する必要がありますが、S2Container内にMapの実装クラスが登録されていれば、
S2Containerがコンテナ内を検索して自動的にプロパティを設定します。ただし、プロパティの型がインターフェースでない場合、
自動バインディングはできません。
s2container.php5/examples/dicon/autobinding/AutoHelloSetterInjection.dicon
<?xml version="1.0" encoding="Shift_JIS"?> <!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN" "http://www.seasar.org/dtd/components21.dtd"> <components> <component class="HashMap"> <initMethod name="put"> <arg>"hello"</arg> <arg>"Hello World!"</arg> </initMethod> </component> <component autoBinding="auto" class="AutoHelloSetterInjection"/> </components>
実行スクリプトの作成
- S2ContainerFactory#create($path)を呼び出してS2Containerを作成します。
- getComponent()を使用して、S2Containerからコンポーネントを取り出します。
- 取得したコンポーネントのメソッドを呼び出します。
<?php require_once(dirname(dirname(dirname(__FILE__))) . '/example.inc.php'); require_once('Hello.class.php'); require_once('Map.class.php'); require_once('HashMap.class.php'); require_once('AutoHelloSetterInjection.class.php'); $PATH = EXAMPLE_DIR . "/dicon/autobinding/AutoHelloSetterInjection.dicon"; $container = S2ContainerFactory::create($PATH); $hello = $container->getComponent('Hello'); $hello->showMessage(); ?>
実行結果
HashMapの値が表示されていることから、自動的にプロパティを設定していることが確認できます。
% php AutoHelloSetterInjection.php Hello World! %
この演習は、s2container.php5/examples/dicon/autobinding以下に用意されています。