diconファイルのincludeパス設定
diconファイルのincludeタグのpath属性では、先頭に%...%で囲むことで定数を埋め込むことができます。
define(DICON_DIR,'/path/to/dir'); //定義済みとする
<components>
<include path="%DICON_DIR%/bar.dicon"/>
</components>
注) パスの先頭の%...%のみ展開されます。
ログ設定
SimpleLogger
S2Logger クラスの getLogger メソッドは、デフォルトでは SimpleLogger のインスタンスを返します。 SimpleLogger はデフォルトで標準出力にログを表示します。ログレベルは DEBUG、INFO、WARN、ERROR、FATAL の 5 つです。 ログレベルの設定は S2CONTAINER_PHP5_LOG_LEVEL 定数で行います。
<?php
require_once(dirname(dirname(dirname(__FILE__))) . '/example.inc.php');
define('S2CONTAINER_PHP5_LOG_LEVEL',S2Container_SimpleLogger::DEBUG);
$logger = S2Container_S2Logger::getLogger('simpleLogClient.php');
$logger->debug('test debug');
$logger->info ('test info ');
$logger->warn ('test warn ');
$logger->error('test error');
$logger->fatal('test fatal');
?>
S2CONTAINER_PHP5_SIMPLE_LOG_FILE 定数にログファイルを設定することで、ログをファイルに出力することができます。このサンプルは examples/misc/logger/simpleLogClient.php にあります。
Zend_Log を使用する ( 1.2 系 )
Zend_Log を使用する場合は、S2Logger クラスの LOGGER_FACTORY 変数に S2Container_ZendLoggerFactory を設定します。
<?php
require_once(dirname(dirname(dirname(__FILE__))) . '/example.inc.php');
require_once('Zend/Log.php');
require_once('Zend/Log/Writer/Stream.php');
require_once('Zend/Log/Filter/Priority.php');
define('S2CONTAINER_PHP5_LOG_LEVEL', Zend_Log::DEBUG);
S2Container_S2Logger::$LOGGER_FACTORY = 'S2Container_ZendLoggerFactory';
S2Container_S2Logger::setLoggerFactory(null);
$logger = S2Container_S2Logger::getLogger('s2base_zf');
$logger->addWriter(new Zend_Log_Writer_Stream(dirname(__FILE__) . '/zendLog.log'));
$logger->addFilter(new Zend_Log_Filter_Priority(S2CONTAINER_PHP5_LOG_LEVEL));
$logger->debug ('test debug');
$logger->info ('test info ');
$logger->notice('test notice ');
$logger->warn ('test warn ');
$logger->err ('test err ');
$logger->crit ('test fatal');
$logger->alert ('test alert ');
$logger->emerg ('test emerg ');
?>
このサンプルは examples/misc/logger/zendLogClient.php にあります。
log4phpを使用する
log4php を使用する場合は、S2Logger の LOGGER_FACTORY 変数に S2Container_Log4phpLoggerFactory を設定します。 ログレベルや出力形式等の設定は、log4php.properties ファイルで行います。
<?php
require_once(dirname(dirname(dirname(__FILE__))) . '/example.inc.php');
define('LOG4PHP_DIR', dirname(__FILE__) . '/log4php-***/src/log4php');
define('LOG4PHP_CONFIGURATION', dirname(__FILE__) . '/log4php.properties');
require_once(LOG4PHP_DIR . '/LoggerManager.php');
S2Container_S2Logger::$LOGGER_FACTORY = 'S2Container_Log4phpLoggerFactory';
$logger = S2Container_S2Logger::getLogger('log4phpClient.php');
$logger->debug('test debug');
$logger->info ('test info ');
$logger->warn ('test warn ');
$logger->error('test error');
$logger->fatal('test fatal');
?>
このサンプルは examples/misc/logger/log4phpClient.php にあります。
__set()でのセッター・インジェクション
PHP5から追加された__set()を使用して、セッター・インジェクションを行うことができます。
- プロパティが明示的に指定されている (diconファイルで propertyタグが記述されている)
- インジェクション対象クラスがセッターメソッドを実装していない
- インジェクション対象クラスが__set()を実装している
実装クラスの作成
- セッター・メソッド(setMessageA)を定義します。
- __set()を実装します。
- showMessage()を実装します。
$messageBプロパティのセッターメソッドは定義していません。
<?php
class HelloImpl {
private $messageA = "";
private $messageB = "";
function HelloImpl() {}
function setMessageA($messageA){
$this->messageA = $messageA;
}
function __set($name,$val){
$this->$name = $val;
}
function showMessage(){
print "{$this->messageA} {$this->messageB} \n";
}
}
?>
diconファイルの作成
- componentタグでコンポーネントを定義します。
- componentタグの子タグのpropertyタグでコンポーネントのプロパティ値を定義します。
s2container.php5/examples/extension/uuset/uuset.dicon
<components>
<component class="HelloImpl">
<property name="messageA">"Hello"</property>
<property name="messageB">"World"</property>
</component>
</components>
実行スクリプトの作成
- S2ContainerFactory#create($path)を呼び出してS2Containerを作成します。
- getComponent()を使用して、S2Containerからコンポーネントを取り出します。
- 取得したコンポーネントのメソッドを呼び出します。
s2container.php5/examples/extension/uuset/uusetClient.php
<?php
require_once(dirname(__FILE__) . '/uuset.inc.php');
$PATH = EXAMPLE_DIR . "/extension/uuset/uuset.dicon";
$container = S2ContainerFactory::create($PATH);
$hello = $container->getComponent('HelloImpl');
$hello->showMessage();
?>
実行結果
propertyタグで指定した文字列が正しく表示されていることが確認できます。
% php uusetClient.php Hello World %このexampleは、s2container.php5/examples/extension/uuset/以下に用意されています。
データベース接続
データベースへの接続フレームワークをextennsionとして含めています。
以降の説明では、以下のサンプルテーブルを用います。 サンプルテーブルを作成する demo.sql は s2container.php5/src/s2container.php5/org/seasar/extension/db/sql/ にあります。
テーブル:EMP| カラム名 | 論理名 | 型 | NotNull | 主キー |
|---|---|---|---|---|
| EMPNO | 従業員番号 | NUMBER | 〇 | 〇 |
| ENAME | 従業員名 | VARCHAR | ||
| JOB | 仕事 | VARCHAR | ||
| MGR | 上司 | NUMBER | ||
| HIREDATE | 雇用日 | DATE | ||
| SAL | 給料 | NUMBER | ||
| COMM | 手数料 | NUMBER | ||
| DEPTNO | 部署番号 | NUMBER | ||
| TSTAMP | タイムスタンプ | TIMESTAMP |
テーブル:DEPT
| カラム名 | 論理名 | 型 | NotNull | 主キー |
|---|---|---|---|---|
| DEPTNO | 部署番号 | NUMBER | 〇 | 〇 |
| DNAME | 部署名 | VARCHAR | ||
| LOC | ロケーション | VARCHAR | ||
| VERSIONNO | バージョン番号 | NUMBER |
DataSourceについて
pdo.dicon テンプレート
pdo.diconのテンプレートを以下に示します。 dataSourceコンポーネントのdsnプロパティを、ご使用のデータベースに接続できる値に設定して下さい。
<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components namespace="pdo">
<component name="dataSource" class="S2Container_PDODataSource">
<property name="dsn">"mysql:host=localhost; port=3306; dbname=s2container"</property>
<property name="user">"root"</property>
<property name="password">"test"</property>
<property name="option">array('foo'=>'bar')</property>
</component>
</components>
使用方法
サンプルとして、引数で受け取ったDEPTNO値でDEPTテーブルを検索し、その結果を返すDAOを実装してみます。
この演習は、s2container.php5/examples/extension/db/以下に用意されています。
インタフェースの定義
- DeptDaoインタフェースを定義します。
- DEPTNO値で検索を行う findDeptByDeptnoメソッドを定義します。
<?php
interface DeptDao {
function findDeptByDeptno($deptno);
}
?>
実装クラスの作成
- DeptDaoインタフェースを implements する DeptDaoImplクラスを作成します。
- コンストラクタ引数で S2Container_DataSource を受け取るようにします。
- findDeptByDeptno メソッドを実装します。データベースへのコネクションは、DataSourceより取得します。
<?php
class DeptDaoImpl implements DeptDao {
private $dataSource;
function DeptDaoImpl(S2Container_DataSource $dataSource) {
$this->dataSource = $dataSource;
}
function findDeptByDeptno($deptno){
$db = $this->dataSource->getConnection();
$result = $db->query("select * from dept where deptno = '{$deptno}';");
$row = $result->fetchRow();
$this->dataSource->disconnect($db);
return $row;
}
}
?>
diconファイルの作成
deptDao.dicon を作成し、pdo.dicon を include します。
<components>
<include path="%S2CONTAINER_PHP5%/org/seasar/extension/db/pdo.dicon"/>
<component name="deptDao" class="DeptDaoImpl"/>
</components>
実行スクリプトの作成
- deptDao.diconを指定してコンテナを作成します。
- コンテナより、deptDaoコンポーネントを取得します。
- DEPTNO(10) で findDeptByDeptno メソッドを呼び出します。
dataSourceClient.php
<?php
require_once(dirname(__FILE__) . '/db.inc.php');
$PATH = EXAMPLE_DIR . "/extension/db/deptDao.dicon";
$container = S2ContainerFactory::create($PATH);
$dao = $container->getComponent('deptDao');
$result = $dao->findDeptByDeptno(10);
print_r($result);
?>
実行結果
% php dataSourceClient.php
Array
(
[0] => 10
[1] => ACCOUNTING
[2] => NEW YORK
[3] => 0
)
%
S2Unit
S2では、コンテナを使った開発のテストを楽しくおこなえるようにテスティングフレームワークが組み込まれています。 PHPUnit2、SimpleTestを拡張しています。主な機能は以下のとおりです。
- テストメソッド(testXxx)ごとに自動的にS2Containerを作成します。
- S2Containerに対するregister()、getComponent()、include() が用意されています。
- TestCaseに public なフィールドがあると、フィールド名と同じ名前のコンポーネントがコンテナに存在すれば自動的にセットされます。
- テストメソッドが終わると自動セットされた値は自動的にクリア( null をセット)されます。
- テストメソッド( testXxx )に対応する setUpXxx()、tearDownXxx() を定義しておくと、setUp()の後、tearDown()の前に自動的に呼び出されます。個別のテストメソッドごとの初期化・終了処理を簡単に行えるようになります。
Example
Pear PHPUnit2 を拡張した S2Container_S2PHPUnit2TestCase を用います。
このサンプルは、s2container.php5/examples/extension/unit/以下にあります。
テスト対象
s2container.php5/examples/extension/unit/src/foo/FooLogic.class.php
<?php
class FooLogic {
function FooLogic() {
}
function showYear(){
return 2005;
}
}
?>
diconファイル
s2container.php5/examples/extension/unit/src/foo/foo.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="logic" class="FooLogic"/>
</components>
テストクラス
s2container.php5/examples/extension/unit/test/phpunit2/foo/FooLogicTest.class.php
<?php
class FooLogicTest extends S2Container_S2PHPUnit2TestCase {
public $logic; //--- dicon ファイルに logic という名前のコンポーネントが存在すれば設定されます
function __construct($name) {
parent::__construct($name);
}
function setUp(){
$this->includeDicon(UNIT_EXAMPLE . "/src/foo/foo.dicon"); //--- dicon ファイルを include します
}
function testShowYear(){
$year = $this->logic->showYear();
$this->assertEquals($year , 2005);
}
}
?>
s2container.php5/examples/extension/unit/test/phpunit2/foo/FooAllTest.class.php
<?php
class FooAllTest {
public static function main() {
PHPUnit2_TextUI_TestRunner::run(self::suite());
}
public static function suite() {
$suite = new PHPUnit2_Framework_TestSuite();
$suite->addTestSuite('FooLogicTest');
return $suite;
}
}
?>
実行スクリプト
s2container.php5/examples/extension/unit/test/phpunit2/foo/fooTests.php
<?php
define('PHPUnit2_MAIN_METHOD', 'FooAllTest::main()');
require_once 'PHPUnit2/Framework/TestSuite.php';
require_once 'PHPUnit2/TextUI/TestRunner.php';
FooAllTest::main();
?>
実行結果
% php allTests.php TEST : FooLogicTest::testShowYear ------------------------------------ . Time: 0.368033 OK (1 test) %
SimpleTest を用いた同様のサンプルが s2container.php5/examples/extension/unit/test/以下にあります。
S2ContainerClassLoader
S2Container.PHP5では、クラス定義の読み込みを S2ContainerClassLoader が管理します。 S2ContainerClassLoader には importメソッドが定義されており、任意のクラスを登録できます。登録されたクラスは、__autoload関数内で読み込まれます。
クラス定義ファイルを指定する
<?php
S2ContainerClassLoader::import('/path/to/Hoge.class.php');
S2ContainerClassLoader::import('/path/to/Foo.php');
?>
クラス名は指定されたファイル名の先頭から「.」までになります。Hoge.class.phpの場合は「Hoge」となります。
クラス名を指定する
<?php
S2ContainerClassLoader::import('/path/to/Hoge.class.php','Hoge');
S2ContainerClassLoader::import('/path/to/classes.php','Foo');
S2ContainerClassLoader::import('/path/to/classes.php','Bar');
?>
importメソッドの第二引数でクラス名を指定できます。
ディレクトリを指定する
<?php
S2ContainerClassLoader::import('/path/to/dir');
?>
指定されたディレクトリにあるクラス定義ファイルをimportします。
クラス定義の配列を使用する
<?php
$classes = array('Hoge'=>'/path/to/Hoge.class.php',
'Foo'=>'/path/to/classes.php');
S2ContainerClassLoader::import($classes);
?>
クラス名をキーとしてクラス定義ファイルが指定された連想配列をimportします。
S2Container_CacheSupport
| 警告 |
| この拡張モジュールは 実験的 なものです。この拡張モジュールの動作・関数名・その他ドキュメントに書かれている事項は、将来変更される可能性があります。 |
S2Container_CacheSupport では、S2ContainerFactory で生成される S2Container インスタンスの serialize データと、S2AOP で生成されるの AopProxy コードをキャッシュします。S2Container_CacheSupportの実装クラスとして、S2Container_PearCacheLiteSupport、S2Container_MemcacheSupport、S2Container_ZendCacheSupport があります。どの CacheSupport クラスを使用するかは、S2CONTAINER_PHP5_CACHE_SUPPORT_CLASS 定数で指定します。 デフォルトは、S2Container_PearCacheLiteSupport です。
S2Container_PearCacheLiteSupport
S2Container_PearCacheLiteSupport は、PEAR Cache_Lite を使用してキャッシュします。 PEAR Cache_Lite を別途インストールして下さい。S2Container_PearCacheLiteSupport を有効にするため、S2CONTAINER_PHP5_CACHE_LITE_INI 定数を定義します。S2CONTAINER_PHP5_CACHE_LITE_INI 定数の設定値は Cache_Lite のオプションを指定する INI 形式ファイルへのパスになります。
<?php
require_once('S2Container/S2Container.php');
define('S2CONTAINER_PHP5_CACHE_LITE_INI', '/path/to/cache_lite.ini');
?>
Cache_Lite のオプションを指定する INI 形式ファイルは次の3つのセクションを持ちます。
- [default]
このセクションで設定した値は、[container] セクションと [aop] セクションのデフォルト値となります。 - [container]
S2Container インスタンスのキャッシュについての固有オプションを設定します。 - [aop]
S2AOP で生成されるの AopProxy コードのキャッシュについての固有オプションを設定します。
各セクションで設定する Cache_Lite オプションについてはこちらを参照下さい。
S2Container_PearCacheLiteSupport を用いたサンプルは、s2container.php5/examples/extension/cache/pearCacheLiteClient.php にあります。サンプルで使用している オプション設定 INI ファイルは次になります。( cacheLite.ini )
[default]
cacheDir = "%EXAMPLE_DIR%/extension/cache/var/" <-- ここで設定したキャッシュディレクトリは、
container と aop に反映されます。
[container] 先頭に%...%で囲むことで定数を埋め込むことができます。
caching = "true"
lifeTime = "3600"
[aop]
caching = "true"
lifeTime = "7200"
S2Container_MemcacheSupport
S2Container_MemcacheSupport は、memcachedサーバにキャッシュを保存します。 S2Container_MemcacheSupport を使用する場合は、memcache 拡張モジュールを導入しておく必要があります。 MemcacheSupport 使用する場合は次のように S2CONTAINER_PHP5_CACHE_SUPPORT_CLASS 定数を定義します。
<?php
require_once('S2Container/S2Container.php');
define('S2CONTAINER_PHP5_CACHE_SUPPORT_CLASS', 'S2Container_MemcacheSupport');
?>
S2Container_MemcacheSupport で設定できるオプションは以下になります。詳細な説明などはmemcache 拡張モジュールの項を参照してください。
| 設定キー | 説明 |
|---|---|
host |
memcachedが起動しているホストを指定します。デフォルトはlocalhostになっています。 |
port |
memcachedへ接続するためのポート番号を指定します。デフォルトは11211になっています。 |
timeout |
memcachedへ接続する際に用いる値です。数値は秒単位で指定します。 |
cache_compress |
memcachedへ保存する際に保存する値を圧縮するかどうかをbooleanで指定します。
デフォルトはfalse(圧縮を行わない)になっています。 圧縮にはzlibを使用します。 |
cache_expire |
memcachedで保存した値の生存期間(有効期限)を設定します。デフォルトは0で有効期限無しとなっています。 設定できる値はunixタイムスタンプか現在からの秒数を指定することができます。 |
オプション設定値を変更する場合は、S2CONTAINER_PHP5_MEMCACHE_INI 定数にオプション設定INIファイルを指定します。
<?php
require_once('S2Container/S2Container.php');
define('S2CONTAINER_PHP5_CACHE_SUPPORT_CLASS', 'S2Container_MemcacheSupport');
define('S2CONTAINER_PHP5_MEMCACHE_INI', '/path/to/memcached.ini');
?>
Memcached のオプションを指定する INI 形式ファイルは次の3つのセクションを持ちます。
- [default]
このセクションで設定した値は、[container] セクションと [aop] セクションのデフォルト値となります。 - [container]
S2Container インスタンスのキャッシュについての固有オプションを設定します。 - [aop]
S2AOP で生成されるの AopProxy コードのキャッシュについての固有オプションを設定します。
S2Container_MemcacheSupport を用いたサンプルは、s2container.php5/examples/extension/cache/memcachedClient.php にあります。 サンプルで使用している オプション設定 INI ファイルは次になります。( memcached.ini )
[default] host = "localhost" port = "11211" cache_compress = "false" [container] host = "ContinerHost" cache_compress = "false" cache_expire = "0" [aop] host = "AopHost" cache_compress = true" timeout = "10"
S2Container_ZendCacheSupport ( 1.2 系 )
S2Container_ZendCacheSupport は、Zend_Cache を使用してキャッシュします。 Zend_Cache を別途インストールして下さい。S2Container_ZendCacheSupport を有効にするため、S2CONTAINER_PHP5_CACHE_SUPPORT_CLASS 定数と S2CONTAINER_PHP5_ZEND_CACHE_INI 定数を定義します。S2CONTAINER_PHP5_ZEND_CACHE_INI 定数の設定値は Zend_Cache のオプションを指定する Zend_Config_Ini 形式ファイルへのパスになります。
<?php
require_once('S2Container/S2Container.php');
define('S2CONTAINER_PHP5_CACHE_SUPPORT_CLASS', 'S2Container_ZendCacheSupport');
define('S2CONTAINER_PHP5_ZEND_CACHE_INI', '/path/to/zend_cache.ini');
?>
Zend_Cache のオプションを指定する INI 形式ファイルは次の3つのセクションを持ちます。
- [default]
このセクションで設定した値は、[container] セクションと [aop] セクションのデフォルト値となります。 - [container]
S2Container インスタンスのキャッシュについての固有オプションを設定します。 - [aop]
S2AOP で生成されるの AopProxy コードのキャッシュについての固有オプションを設定します。
各セクションでZend_Cache オプションを、フロントエンド、バックエンドごとに設定します。
S2Container_ZendCacheSupport を用いたサンプルは、s2container.php5/examples/extension/cache/zendCacheClient.php にあります。サンプルで使用している オプション設定 INI ファイルは次になります。( zendCache.ini )
[default] frontend.name = "Core" backend.name = "File" backend.cache_dir = "%EXAMPLE_DIR%/extension/cache/var/" <-- 先頭に%...%で囲むことで定数を埋め込むことができます。 [container : default] frontend.caching = "false" frontend.lifetime = "3600" [aop : default] frontend.caching = "true" frontend.lifetime = "7200"
自動登録
FileSystemComponentAutoRegister
自動バインディングにより、DIの設定はほぼ自動化できます。 さらに、コンポーネントの登録も自動化してしまおうというのが、コンポーネントの自動登録機能です。 定数アノテーションまたはコメントアノテーションを使って細かく制御することも可能です。
| プロパティ | 説明 |
|---|---|
| instanceMode | 自動登録されるコンポーネントに適用するInstanceModeを指定します。 |
autoNaming |
クラス名からコンポーネント名を自動的に決定するコンポーネント。 S2Container_AutoNamingインターフェースを実装している必要があります。 デフォルトは、S2Container_DefaultAutoNamingクラスのインスタンスになります。 |
| メソッド | 説明 |
|---|---|
addClassPattern |
自動登録したいクラスパターンを登録します。引数を2つ持ちます。最初の引数は、コンポーネントのクラス定義ファイルを検索するディレクトリパスです。サブディレクトリも再帰的に検索します。クラスファイルのSUFFIXは「.class.php」です。クラス名とファイル名は一致しなければいけません。2番目の引数はクラス名です。正規表現が使えます。「,」区切りで複数記述することもできます。 |
addIgnoreClassPattern |
自動登録したくないクラスパターンを登録します。引数を1つ持ちます。引数はクラス名です。正規表現が使えます。カンマ「,」区切りで複数記述することもできます。 |
AutoNaming
コンポーネントの名前はAutoNamingにより制御します。
DefaultAutoNaming
クラス名の最後が Impl または Bean で終わっていたら削除し、先頭を小文字にした名前をコンポーネントの名前に設定します。
例えば、HogeImplクラスの場合、コンポーネント名は hoge になります。
| プロパティ | 説明 |
|---|---|
decapitalize |
コンポーネント名の先頭を小文字にする場合はtrueを指定します。デフォルトはtrueです。 |
| メソッド | 説明 |
|---|---|
setCustomizedName |
デフォルトのルールに従わないクラスを登録します。最初の引数は、クラス名です。 2番目の引数は、コンポーネント名です。 |
addIgnoreClassSuffix |
クラス名の末尾から削除する部分を指定します。デフォルトで Impl および Bean が登録されています。 |
addReplaceRule |
正規表現による置換ルールを追加します。最初の引数は正規表現です。2番目の引数は置換文字列です。 |
clearReplaceRule |
setCustomizedName、addIgnoreClassSuffix、addReplaceRuleで登録した変換規則をクリアします。デフォルトで登録されている Impl および Bean もクリアされます。 |
s2container.php5/examples/extension/autoregister/autoFile.dicon
<components>
<component class="S2Container_FileSystemComponentAutoRegister">
<property name="instanceMode">"singleton"</property>
<property name="autoNaming">
<component class="S2Container_DefaultAutoNaming">
<initMethod name="setCustomizedName">
<arg>"HogeService"</arg>
<arg>"service"</arg>
</initMethod>
</component>
</property>
<initMethod name="addClassPattern">
<arg>"%EXAMPLE_DIR%/extension/autoregister/autoFile"</arg>
<arg>".+Bean,.+Service"</arg>
</initMethod>
<initMethod name="registerAll"/>
</component>
</components>
*** S2Container_FileSystemComponentAutoRegister::registerAllメソッドをinitMthodとして設定して下さい。
アノテーション
定数アノテーションまたはコメントアノテーションを用いて自動登録するコンポーネントを細かく設定することができます。定数アノテーションとコメントアノテーションの選択は、S2CONTAINER_PHP5_ANNOTATION_HANDLER定数で設定します。S2CONTAINER_PHP5_ANNOTATION_HANDLER定数に「S2Container_ConstantAnnotationHandler」または 「S2Container_CommentAnnotationHandler」を定義して下さい。デフォルトは定数アノテーションです。
Componentアノテーション
componentタグのかわりに使えるのが、Componentアノテーションです。
定数アノテーションは以下のようになります。
<?php
class HogeImpl {
const COMPONENT = "name = hogeComp,
instance = prototype,
autoBinding = auto";
.....
}
?>
コメントアノテーションは以下のようになります。
<?php
/**
* @S2Container_ComponentAnnotation(name = hogeComp,
* instance = prototype,
* autoBinding = auto)
*/
class HogeImpl {
.....
}
?>
s2container.php5/examples/extension/autoregister/compAnnoClient.php を参照下さい。
Bindingアノテーション
propertyタグのかわりに使えるのが、Bindingアノテーションです。
Bindingアノテーションで設定される値はコンポーネント名またはexpression(PHP式)として扱われます。
プロパティ名 + _BINDING 定数名
<?php
class HogeImpl {
.....
private $value;
const value_BINDING = '" string value must be quoted "';
public function setValue($value){
$this->value = $value;
}
public function getValue(){
return $this->value;
}
.....
}
?>
コメントアノテーションは以下のようになります。
<?php
class HogeImpl {
.....
private $value = null;
/**
* @S2Container_BindingAnnotation('" string value must be quoted "')
*/
public function setValue($value){
$this->value = $value;
}
public function getValue(){
return $this->value;
}
.....
}
?>
s2container.php5/examples/extension/autoregister/bindAnnoClient.php を参照下さい。
Aspectアノテーション
aspectタグのかわりに使えるのが、Aspectアノテーションです。aspectタグと異なり、複数定義することはできないので、複数のインターセプタを適用したい場合は、InterceptorChainを使ってください。pointcutを指定しないときは、そのクラスが実装しているすべてのインターフェースのメソッドが対象になります。 複数のpointcutを指定する場合はスペース区切りとして下さい。
定数アノテーションは以下のようになります。
<?php
class HogeImpl {
.....
const ASPECT = "interceptor = new S2Container_TraceInterceptor() ,
pointcut = m1 m2 ";
public function m1($a,$b){
return $a + $b;
}
public function m2($a,$b){
return $a * $b;
}
.....
}
?>
コメントアノテーションは以下のようになります。
<?php
/**
* @S2Container_AspectAnnotation (interceptor = new S2Container_TraceInterceptor() ,
* pointcut = m1)
*/
class HogeImpl {
.....
public function m1($a,$b){
return $a + $b;
}
/**
* @S2Container_AspectAnnotation(interceptor =
* new S2Container_TraceInterceptor());
*/
public function m2($a,$b){
return $a * $b;
}
.....
}
?>
s2container.php5/examples/extension/autoregister/aspectAnnoClient.php を参照下さい。
InitMethodアノテーション
initMethodタグのかわりに使えるのが、InitMethodアノテーションです。 initMethodタグと異なり、PHP式を書いたり、引数を設定することはできません。 初期化メソッドを複数指定したい場合は、カンマ(,)で区切ってください。
定数アノテーションは以下のようになります。
<?php
class HogeImpl {
.....
const INIT_METHOD = 'initA,initB';
public function initA(){
print __METHOD__ . " called.\n";
}
public function initB(){
print __METHOD__ . " called.\n";
}
.....
}
?>
コメントアノテーションは以下のようになります。
<?php
class HogeImpl {
.....
/**
* @S2Container_InitMethodAnnotation
*/
public function initA(){
print __METHOD__ . " called.\n";
}
/**
* @S2Container_InitMethodAnnotation
*/
public function initB(){
print __METHOD__ . " called.\n";
}
.....
}
?>
s2container.php5/examples/extension/autoregister/methodAnnoClient.php を参照下さい。
AspectAutoRegister
コンポーネントの自動登録により、コンポーネントの登録は自動化できます。 さらに、アスペクトの登録も自動化してしまおうというのが、アスペクトの自動登録機能です。 コンポーネントの自動登録と組み合わせる場合は、 コンポーネントの自動登録の設定よりも後に、アスペクトの自動登録の設定を記述する必要があります。
| プロパティ | 説明 |
|---|---|
interceptor |
インターセプタを指定します。複数のインターセプタを指定したい場合は、InterceptorChainを使ってください。 |
pointcut |
インターセプタを適用するメソッドをカンマ区切りで指定します。pointcutを指定しない場合は、コンポーネントが実装しているインターフェースのすべてのメソッドが対象になります。メソッド名には正規表現も使えます。 |
| メソッド | 説明 |
|---|---|
addClassPattern |
自動登録したいクラスパターンを登録します。引数はクラス名です。正規表現が使えます。「,」区切りで複数記述することもできます。 |
addIgnoreClassPattern |
自動登録したくないクラスパターンを登録します。引数はクラス名です。正規表現が使えます。「,」区切りで複数記述することもできます。 |
s2container.php5/examples/extension/autoregister/autoAspect.dicon
<components>
<component class="S2Container_AspectAutoRegister">
<property name="interceptor">new S2Container_TraceInterceptor()</property>
<property name="pointcut">"m1,m2"</property>
<initMethod name="addClassPattern">
<arg>".+Service"</arg>
</initMethod>
<initMethod name="registerAll"/>
</component>
<component class="HogeService"/>
<component class="HogeBean"/>
</components>
*** S2Container_AspectAutoRegister::registerAllメソッドをinitMthodとして設定して下さい。*** 他のコンポーネント定義より先に定義する必要があります。
*** S2Container_FileSystemComponentAutoRegisterと併用する場合は、S2Container_FileSystemComponentAutoRegisterの定義が先になります。
InterfaceAspectAutoRegister
| プロパティ | 説明 |
|---|---|
interceptor |
インターセプタを指定します。複数のインターセプタを指定したい場合は、InterceptorChainを使ってください。 |
targetInterface |
指定したインターフェースを実装しているコンポーネントに対して、アスペクトを適用します。 |
s2container.php5/examples/extension/autoregister/autoInterface.dicon
<components>
<component class="S2Container_InterfaceAspectAutoRegister">
<property name="interceptor">new S2Container_TraceInterceptor()</property>
<property name="targetInterface">"HogeService"</property>
<initMethod name="registerAll"/>
</component>
<component class="HogeServiceImpl"/>
<component class="HogeBeanImpl"/>
</components>
*** S2Container_InterfaceAspectAutoRegister::registerAllメソッドをinitMthodとして設定して下さい。*** 他のコンポーネント定義より先に定義する必要があります。
*** S2Container_FileSystemComponentAutoRegisterと併用する場合は、S2Container_FileSystemComponentAutoRegisterの定義が先になります。
コメントアノテーション
コメントアノテーションは、PhpDocに記述されたアノテーション情報を読み込むフレームワークです。
コンポーネントの自動登録で使用できます。
S2Container_Annotations
S2Container_Annotationsクラスは3つのStaticメソッドを実装しています。
| メソッド | 説明 |
|---|---|
getAnnotations |
クラスまたはメソッドのすべてのアノテーションを取得します。第1引数はクラス名です。 メソッドのアノテーションを取得する場合は第2引数でメソッド名を指定します。 |
getAnnotation |
クラスまたはメソッドの指定したアノテーションを取得します。第1引数でアノテーションタイプを指定します。 第2引数でクラス名、第3引数でメソッド名を指定します。 |
isAnnotationPresents |
クラスまたはメソッドに指定したアノテーションが存在するかどうかを調べます。 第1引数でアノテーションタイプを指定します。第2引数でクラス名、第3引数でメソッド名を指定します。 |
アノテーションの記述
PhpDocに記述されるコメントアノテーションは以下のフォーマットになります。
/**
* @Seasar
* @Foo ( 2006 )
* @Bar ( abc, 2006 )
* @Hoge ( name = abc, year = 2006 )
*/
class Hello {
/**
* @Bar ( xyz, 2000 )
* @Hoge ( name = xyz, year = 2000 )
*/
public function greeting(){
print "Hello ! \n";
}
}
アノテーションタイプは予めクラス定義が読み込まれている必要があります。上記の場合、アノテーションタイプは、Seasar、Foo、Bar、Hogeクラスになります。
<?php
class Seasar{}
class Foo{
public $value = "default value";
}
class Bar{
public $value;
}
class Hoge {
public $name = "default name";
public $year = 2000;
}
?>
アノテーションの引数はアノテーションタイプのプロパティに設定されます。イコール(=)とカンマ(,)は区切り文字として使用されます。上記の例では、@Seasarアノテーションは引数をとりません。@Fooと@Barアノテーションは値引数を持ちます。値引数が1つの場合は(@Fooの場合)、valueプロパティにそのまま代入されます。値引数が複数の場合(@Barの場合)、valueプロパティに値の配列として代入されます。最後の@Hogeは引数としてキーと値のペアーをとります。キーがプロパティ名となり、値が代入されます。
アノテーションの取得
S2Container_Annotations::getAnnotations()
s2container.php5/examples/extension/annotation/annoClient.php
...
$annos = S2Container_Annotations::getAnnotations('Hello','greeting');
print_r($annos);
...
Helloクラスのgreetingメソッドに付いているアノテーションをすべて取得します。
> php annoClient.php
Array
(
[Bar] => Bar Object
(
[value] => Array
(
[0] => xyz
[1] => 2000
)
)
[Hoge] => Hoge Object
(
[name] => xyz
[year] => 2000
)
)
>
S2Container_Annotations::getAnnotation()
s2container.php5/examples/extension/annotation/annoClient.php
...
$anno = S2Container_Annotations::getAnnotation('Foo','Hello');
print_r($anno);
$anno = S2Container_Annotations::getAnnotation('Bar','Hello');
print_r($anno);
...
Helloクラスに付いているFooとBarアノテーションを取得します。
> php annoClient.php
Foo Object
(
[value] => 2006
)
Bar Object
(
[value] => Array
(
[0] => abc
[1] => 2006
)
)
>
S2Container_Annotations::isAnnotationPresent()
s2container.php5/examples/extension/annotation/annoClient.php
...
if(S2Container_Annotations::isAnnotationPresent('Seasar','Hello')){
print "Seasar annotation exists at hello class.\n";
}
if(!S2Container_Annotations::isAnnotationPresent('Seasar','Hello','greeting')){
print "Seasar annotation not exists at greeting method.\n";
}
...
HelloクラスとgreetingメソッドにSeasarアノテーションが付いているかどうかを調べます。
> php annoClient.php Seasar annotation exists on hello class. Seasar annotation not exists on greeting method. >
Yaml形式によるDicon定義
S2Container.PHP5-1.1.2以降では、通常のDicon定義のXML形式以外にYaml形式のサポートをしています。
Dicon定義ファイルの拡張子は ".yml" を用います。
Yaml形式によるDicon定義を使うには、Spycを用います。S2Container.PHP5からは Spycを読み込みにいきませんので、Yaml形式のDicon定義を使う場合には予め読み込んでおく必要があります。
Yaml形式によるDicon定義は通常のXML定義とほぼ同等です。以下に簡単なDicon定義を示します。
components:
- component: .
name: hello
- class: HelloConstructorInjection
- arg: Hello World!
Components定義(任意)
トップレベルにおいて省略可能な定義です。もしnamespaceなどの定義が無い場合は省略することが可能です。
components:
:
:
Namespace定義(任意)
名前空間を指定することができます。PHPの識別子として使えるものにします。
components:
namespace: hoge
:
:
:
Include定義(任意)
分割されたS2Containerの定義を取り込む場合に使います。
components:
include: [%DICON_DIR%/foo.yml]
include: [%DICON_DIR%/foo.yml, %DICON_DIR%/bar.yml]
include:
- %DICON_DIR%/foo.yml
include:
- %DICON_DIR%/foo.yml
- %DICON_DIR%/bar.yml
Component定義(任意)
コンポーネントを定義します。
classキー(任意)
クラス名を指定します。直接キーの値としてPHP式を使ってコンポーネントを指定した場合は、class属性を省略することができます。 PHP式を使った場合にclass属性を指定すると、型チェックを行います。
nameキー(任意)
名前を指定することもできます。PHPの識別子として使えるものにします。詳しくは、コンポーネントの取得を参照してください。
instanceキー(任意)
S2Containerがどのようにコンポーネントのインスタンスを管理するのかを指定することができます。 singleton(デフォルト)、prototype、outer、request、sessionを指定することができます。詳しくはインスタンス管理を参照してください。
autoBindingキー(任意)
S2Containerがコンポーネントの依存関係をどのように解決するのかを指定できます。 auto(デフォルト)、constructor、property、noneを指定することができます。詳しくは、自動バインディングを参照してください。
components:
- component: .
- class: hoge
- component: .
name: a
- class: hoge
- component: .
name: b
instance: prototype
- class: hoge
- component: .
name: c
instance: prototype
autoBinding: auto
- class: hoge
Yaml形式によるDicon定義において、複数のcomponentが存在する場合
- component: .のようにcomponentキーの後ろに"."(ドット)を用います。
複数のcomponent定義をする場合は必ず"."(ドット)を付けるようにしてください。
また、classキーにおいては、必ず
- class: classNameとなるように、classキーは"-"(ハイフン)を付けてください。
Arg定義(任意)
Arg定義の説明はXMLのDicon定義と同じですが、 YAML形式のArg定義には2パターンあり、キーの種類は arg:とphp:の2種類が存在します。
argキー
argキーは、通常の文字列として扱われます。
phpキー
phpキーは、PHP式の扱いとなり、phpキーで囲われた値がそのままPHP式に使われます。
もし複数行に渡るPHP式を用いる場合は、
arg: .と
php:>を組み合わせることで複数行のPHP式も使用可能です。
components:
- component: .
- class: AAA
- arg: "val 1"
- arg: "val 2"
- component: .
- class: BBB
- php: d
- arg: "val 2"
- component: .
- class: CCC
- arg: d
- arg: e
- component: .
- class: DDD
- property: .
name: hoge
- arg: .
php:>
$msg1 = "Hello ";
$msg2 = "World";
return $msg1 . $msg2;
Property定義(任意)
componentキーの子として使います。プロパティとして設定される実際の値は、直接キーの値としてPHP式を使います。
nameキー(必須)
プロパティ名を指定します。
components:
- component: .
name: "a"
- class: "AAA"
- property: .
name: "val1"
- arg: "val 1."
- component: .
name: "b"
- class: "BBB"
- property: .
name: "val1"
- arg: "val 1."
- property: .
name: "val2"
- arg: .
- component: .
name: "d"
- class: "DDD"
- component: .
name: "c"
- class: "CCC"
- property: .
name: "val1"
- php: 1+1;
Yaml形式によるDicon定義において、複数のpropertyが存在する場合
- property: .のようにpropertyキーの後ろに"."(ドット)を用います。
複数のproperty定義をする場合は必ず"."(ドット)を付けるようにしてください。
initMethod定義(任意)
componentタグの子タグとして使います。引数は、子タグでargキーを使います。 name属性を書かずにPHP式を使って、コンポーネントのメソッドを呼び出すこともできます。 initMethodが定義されているコンポーネント自身を表す $componentがinitMethodキーの値としてPHP式を記述するだけで有効なオブジェクトとして使えます。
nameキー
メソッド名を指定します。
components:
- component: .
name: "a"
- class: "AAA"
- initMethod: $component->culc(1, 2);
- component: .
- class: "BBB"
- initMethod: .
name: "addMessage"
- arg: Hello
- initMethod: $component->addMessage("World!")
- component: .
name: "mock"
- class: "S2Container_MockInterceptor"
- initMethod: .
name: "setReturnValue"
- arg: add
- arg: "5"
DestroyMethod定義
initMethodタグと同様です。
components:
- component: .
name: "a"
- class: "AAA"
- destroyMethod: .
- php: print 'destroy method expression test.';
Aspect定義
アスペクトをコンポーネントに組み込みます。詳しくは、aspectタグの説明を参照してください。
components:
namespace: AAA
- component: .
- class: "Hoge"
- aspect: .
- component: .
- class: "Foo"
- component: .
- class: "Bar"
- aspect: AAA.mock
- component: .
name: "mock"
- class: "S2Container_MockInterceptor"
- initMethod: .
name: "setReturnValue"
- arg: "add"
- arg: "12"
interType定義(任意)
インタータイプをコンポーネントに組み込みます。詳しくは、S2AOPのinterTypeタグの説明を参照してください。
components:
- component: .
- class: "Hello"
- interType: S2Container_SerializableInterType
- interType: S2Container_PropertyInterType
Meta定義
Meta定義の説明はXMLのDicon定義と同じです。
しかし、YamlでMeta定義を扱う場合、Yamlの豊富な表現力によっていくつものMeta記述が可能です。
components:
- meta: .
name: "m1"
- arg: "m1-val1"
- meta: .
name: "m2"
- php: 1+1
- meta: .
name: "m3"
- php: "n"
- component: .
name: "a"
- class: "AAA"
- meta: .
name: "a1"
- arg: "m2-val2"
- arg: "test value."
- component: .
name: "b"
- class: "BBB"
- arg: "test value."
- meta: .
name: "b1"
- arg: "m1-val1"
- meta: .
name: "b2"
- php: 1+1
- meta: .
name: "b3"
- php: "b"
- component: .
name: "c"
- class: "CCC"
- property: .
name: "cProp1"
- arg: "val 1."
- meta: .
name: "c1"
- arg: "m1-val1"
- meta: .
name: "c2"
- php: 1+1
- meta: .
name: "c3"
- php: b
- component: .
name: "d"
- class: "DDD"
- initMethod: .
name: "dIni1"
- arg: "val 1."
- meta: .
name: "d1"
- arg: "m1-val1"
- meta: .
name: "d2"
- php: 1+1
- meta: .
name: "d3"
- php: "b"
- component: .
name: "e"
- class: "EEE"
- destroyMethod: .
name: "eDest1"
- arg: "end of century."
- meta: .
name: "e1"
- arg: "m1-val1"
- meta: .
name: "e2"
- php: 1+1
- meta: .
name: "e3"
- php: "b"
その他Yaml形式について
Yaml形式によるDicon定義は、XMLのそれよりも省略が可能な形式となっていますが、複雑な階層を持つDicon定義には向いていません。その点は注意してください。
XMLのDicon定義とYamlのDicon定義の対比については、 wiki.s2php5.jp/s2container.php5の DIContainerBuilderの対応が参考になります。