Seasar DI Container with AOP

Extension

diconファイルのincludeパス設定

diconファイルのincludeタグのpath属性では、先頭に%...%で囲むことで定数を埋め込むことができます。

define(DICON_DIR,'/path/to/dir');   //定義済みとする

<components>
    <include path="%DICON_DIR%/bar.dicon"/>
</components>
注) パスの先頭の%...%のみ展開されます。

__set()でのセッター・インジェクション

PHP5から追加された__set()を使用して、セッター・インジェクションを行うことができます。

  • プロパティが明示的に指定されている (diconファイルで propertyタグが記述されている)
  • インジェクション対象クラスがセッターメソッドを実装していない
  • インジェクション対象クラスが__set()を実装している
上記条件に一致する場合に、__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/src/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/src/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/src/examples/extension/uuset/以下に用意されています。

PHP設定ファイル形式のdiconファイル

PHPの設定ファイル(php.ini等)で使用されるフォーマットで、diconファイルを記述します。
セクションの種類は、componentsセクションと各コンポーネントセクションの2つになります。

[components]
namespace = "dao"
.....
.....
.....
[componentA]                +
class = "A"                 |
.....                       |
.....                       |  各コンポーネントセクション
[componentB]                |
.....                       |
.....                       |
.....                       ▽

components セクション

componentsセクションには、3つの設定項目があります。componentsセクションは設定の必要がなければ省略できます。

   ・namespace  :  namespaceを設定します。
   ・include  :  includeするdiconファイルのパスを設定します。include{index}で複数設定します。
   ・meta  :  metaデータを設定します。

[components]
namespace = "dao"
include{0} = "/path/to/aaa.dicon"
include{1} = "/path/to/bbb.dicon"
meta{0}{name} = "metaA"
meta{0}{val}  = "meta data"
・・・
・・・
・・・

component セクション

componentセクションのセクション名には、コンポーネント名を設定します。class項目が省略されている場合、 コンポーネント名がclass名として扱われます。componentセクションには10ヶの設定項目があります。

   ・class : class名を設定します。省略した場合はセクション名をclass名とします。
   ・instance : instanceモードを設定します。
   ・autobinding : 自動バインディングモードを設定します。
   ・exp : PHP式を記述します。
   ・arg : コンストラクタ引数を設定します。
   ・property : プロパティを設定します。
   ・init_method : initMethodを設定します。
   ・destroy_method : destroyMethodを設定します。
   ・aspect : アスペクトを設定します。
   ・meta : metaデータを設定します。

[hello]
class = "Hello"
instance = "singleton"
autobinding = "auto"

arg{0}{val} = "hello world"
arg{1}{ref} = "bye"

property{0}{name} = "message"
property{0}{val} = "hello world 2 !!"

init_method{0}{name} = "initialize"
init_method{0}{arg{0}{val}} = "-1"

aspect{0}{pointcut} = "showMessage"
aspect{0}{exp} = "new S2Container_TraceInterceptor()"

meta{0}{name} = "helloMeta"
meta{0}{ref} = "bye"

[bye]
class = "Bye"

・・・
・・・
・・・

arg設定

   ・arg{index}{val} = 値を設定
   ・arg{index}{ref} = 参照コンポーネントを指定
   ・arg{index}{exp} = PHP式を記述
   ・arg{index}{meta{0}{val}} = Metaデータを設定
[hello]
class=Hello
arg{0}{val} = "hello world"
arg{1}{ref} = bye
arg{2}{exp} = "array('hello','world','!!')"

[bye]
class = Bye

property設定

   ・property{index}{name} = プロパティ名を設定
   ・property{index}{val} = 値を設定
   ・property{index}{ref} = 参照コンポーネントを指定
   ・property{index}{exp} = PHP式を記述
   ・property{index}{meta{0}{val}} = Metaデータを設定
[hello]
class=Hello

property{0}{name} = "messageA"     --- messageAプロパティに値 Hello を設定
property{0}{val} = "Hello"
property{1}{name} = "messageB"     --- messageBプロパティに値 World を設定
property{1}{val} = "World"
property{2}{name} = "bye"          --- byeプロパティにコンポーネント bye を設定
property{2}{ref} = "bye"

[bye]
class = Bye

init_method設定

   ・init_method{index}{name} = メソッド名を設定
   ・init_method{index}{arg{0}{val}} = メソッド引数を設定
   ・init_method{index}{exp} = PHP式を記述
[hello]
class=Hello

init_method{0}{name} = "showMessage"
init_method{0}{arg{0}{val}} = "Hello"
init_method{0}{arg{1}{val}} = "World"

init_method{1}{exp} = "$component->initialize()"

destroy_method設定

init_method設定と同様です。

aspect設定

   ・aspect{index}{pointcut} = pointcutを設定
   ・aspect{index}{ref} = 参照コンポーネントを設定
   ・aspect{index}{exp} = PHP式を記述
[hello]
class=Hello

aspect{0}{pointcut} = "showMessage"
aspect{0}{ref} = "trace"

[trace]
class = "S2Container_TraceInterceptor"

meta設定

meta{index}{name}でmeta名、meta{index}{val}で値を設定します。

   ・meta{index}{val} = 値を設定
   ・meta{index}{ref} = 参照コンポーネントを指定
   ・meta{index}{exp} = PHP式を記述
[components]
meta{0}{name} = "metaA"
meta{0}{val} = "5"
meta{1}{name} = "metaB"
meta{1}{ref} = hello
meta{2}{name} = "metaC"
meta{2}{exp} = "array('a','b','c')"

[hello]
class = HelloImpl

その他

  • 項目名にクォートは使用できません。 ( arg{0}{'val'}、arg{0}{"val"} など)
  • 設定値は、ダブルクォートで囲むことで改行が有効となります。
  • indexは0からの連番になります。
  • s2container.php5/src/examples/以下の演習で使用するdiconファイルは、XML形式とPHP設定ファイル形式の2種類を用意しています。参照下さい。

データベース接続

データベースへの接続フレームワークを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について

ネイティブのMySQL関数とPostgreSQL関数、Pear DB、ADOdbを用いるデータベース接続について、 それぞれDataSource設定diconファイルのテンプレートが、s2container.php5/src/s2container.php5/org/seasar/extension/db/ にあります。

XML形式 diconファイル INI形式 diconファイル
ネイティブMySQL関数 mysql.dicon mysql.ini
ネイティブPostgreSQL関数 postgres.dicon postgres.ini
Pear DB peardb.dicon peardb.ini
ADOdb adodb.dicon adodb.ini
 ・Pear DB を使用する場合は、予め DB.php をrequireして下さい。
 ・ADOdb を使用する場合は、予め adodb-exceptions.inc.php と adodb.inc.php をrequireして下さい。

peardb.dicon テンプレート

peardb.diconのテンプレートを以下に示します。 dataSourceコンポーネントの各プロパティ設定値を、ご使用のデータベースに接続できる値に設定して下さい。 dsnプロパティが設定されている場合は、dsnプロパティ値が優先されます。

XML形式 peardb.diconファイル

<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container//EN"
"components21.dtd">
<components namespace="peardb">
    <component name="dataSource" class="S2Container_PearDBDataSource">
        <property name="dsn">                                  
            "mysql://hoge:hoge@localhost:3306/s2container"       
        </property>                                            
    </component>

    <component class="S2Container_PearDBSqlHandler"/>
    <component name="dbtx" class="S2Container_PearDBTxInterceptor"/>
    <component name="dao" class="S2Container_SimpleDaoInterceptor"/>
    <component class="S2Container_DaoMetaDataFactoryImpl"/>
    <component name="session" class="S2Container_DBSessionImpl"/>
</components>

INI形式 peardb.iniファイル

[components]
namespace="peardb"

[dataSource]
class="S2Container_PearDBDataSource"

property{0}{name}="dsn"                                         
property{0}{val} ="mysql://hoge:hoge@localhost:3306/s2container"

[S2Container_PearDBSqlHandler]

[dbtx]
class="S2Container_PearDBTxInterceptor"

[dao]
class="S2Container_SimpleDaoInterceptor"

[S2Container_DaoMetaDataFactoryImpl]

[session]
class="S2Container_DBSessionImpl"

使用方法

サンプルとして、引数で受け取ったDEPTNO値でDEPTテーブルを検索し、その結果を返すDAOを実装してみます。
この演習は、s2container.php5/src/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;
    }
}
?>
DataSource->getConnection()の戻り値は、
  ・Pear DBを用いる場合 : DB::connect()の戻り値
  ・ADOdbを用いる場合 : NewADOConnection()の戻り値
  ・MySQL関数を用いる場合 : mysql_connect()の戻り値
  ・PostgreSQL関数を用いる場合 : pg_connect()の戻り値
となります。どのデータベース接続モジュールを使用するかは、以下のdiconファイルで指定します。

diconファイルの作成

Pear DB を用いる場合の diconファイルを作成します。includeタグで peardb.diconをインクルードします。

XML形式 deptDao.dicon

<components>
    <include path="%S2CONTAINER_PHP5%/org/seasar/extension/db/peardb.dicon"/>
    <component name ="deptDao" class="DeptDaoImpl"/>
</components>

INI形式 deptDao.ini

[components]
include{0} = "%S2CONTAINER_PHP5%/org/seasar/extension/db/peardb.dicon"

[deptDao]
class="DeptDaoImpl"

実行スクリプトの作成

  • deptDao.diconを指定してコンテナを作成します。
  • コンテナより、deptDaoコンポーネントを取得します。
  • DEPTNO(10) で findDeptByDeptno メソッドを呼び出します。

dataSourceClient.php

<?php
require_once(dirname(__FILE__) . '/db.inc.php');
$PATH = EXAMPLE_DIR . "/extension/db/deptDao.dicon";
//$PATH = EXAMPLE_DIR . "/extension/db/deptDao.ini";

$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
)
%

TxIntereceptorを使用する

TxInterceptorを使用して、データベースへのトランザクションを管理します。
この演習は、s2container.php5/src/examples/extension/db/以下に用意されています。

インタフェースの定義

  • DeptDaoインタフェースを定義します。
  • DEPTNO値で検索を行う findDeptByDeptnoメソッドを定義します。
<?php
interface DeptDao {
    function findDeptByDeptno($deptno);
}
?>

実装クラスの作成

  • DeptDaoインタフェースを implements する TxDeptDaoImplクラスを作成します。
  • コンストラクタ引数で S2Container_DBSession を受け取るようにします。
  • findDeptByDeptno メソッドを実装します。データベースへのコネクションは、DBSessionより取得します。
データベースへの接続、切断や、トランザクションの開始(BEGIN)、COMMITは、TxInterceptorが行います。 また Exception が throw された場合は、ROLLBACKを実施します。
<?php
class TxDeptDaoImpl implements DeptDao {

    private $session;

    function TxDeptDaoImpl(S2Container_DBSession $session) {
        $this->session = $session;
    }
    
    function findDeptByDeptno($deptno){
        $db = $this->session->getConnection();
        $result = $db->query("select * from dept where deptno = '{$deptno}';"); 
        $row = $result->fetchRow();

        return $row;
    }
}
?>
DBSession->getConnection()の戻り値は、
  ・Pear DBを用いる場合 : DB::connect()の戻り値
  ・ADOdbを用いる場合 : NewADOConnection()の戻り値
  ・MySQL関数を用いる場合 : mysql_connect()の戻り値
  ・PostgreSQL関数を用いる場合 : pg_connect()の戻り値
となります。

diconファイルの作成

Pear DB を用いる場合の diconファイルを作成します。includeタグで peardb.diconをインクルードします。 findDeptByDeptnoメソッドに、dbtx (S2Container_PearDBTxInterceptor) をアスペクトします。

XML形式 txDeptDao.dicon

<components>
    <include path="%S2CONTAINER_PHP5%/org/seasar/extension/db/peardb.dicon"/>
    <component name ="deptDao" class="TxDeptDaoImpl">
        <aspect pointcut="findDeptByDeptno">
            dbtx
        </aspect>
    </component>
</components>

INI形式 txDeptDao.ini

[components]
include{0} = "%S2CONTAINER_PHP5%/org/seasar/extension/db/peardb.dicon"

[deptDao]
class="TxDeptDaoImpl"
aspect{0}{pointcut} = "findDeptByDeptno"
aspect{0}{ref} = "dbtx"

実行スクリプトの作成

  • txDeptDao.diconを指定してコンテナを作成します。
  • コンテナより、deptDaoコンポーネントを取得します。
  • DEPTNO(10) で findDeptByDeptno メソッドを呼び出します。

txClient.php

<?php
require_once(dirname(__FILE__) . '/db.inc.php');

$PATH = EXAMPLE_DIR . "/extension/db/txDeptDao.dicon";
//$PATH = EXAMPLE_DIR . "/extension/db/txDeptDao.ini";

$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
)
%

SimpleDaoInterceptorを使用する (この機能はS2Dao.PHP5 に移ります)

インタフェース定義とSQL文でデータベース接続を行います。
この演習は、s2container.php5/src/examples/extension/db/以下に用意されています。

戻り値が配列の場合

データベース検索結果を配列で取得します。

インタフェースの定義

  • DeptDaoインタフェースを定義します。
  • DEPTNO値で検索を行う findDeptByDeptnoメソッドを定義します。
  • 定数アノテーション(QUERY)で、SQL文を設定します。
<?php
interface DeptDao {
    const findDeptByDeptno_QUERY = 'select * from dept where deptno = \'{$deptno}\'';
    //const findDeptByDeptno_FILE = '%PATH_PREFIX%/path/to/sql/file';  // 外部SQLファイルを指定する場合
    function findDeptByDeptno($deptno);
}
?>

各メソッドが発行するSQL文を指定する方法は3通りあります。
   ・定数アノテーション: メソッド名_QUERY に記述する (上記サンプル)
   ・定数アノテーション: メソッド名_FILE で外部ファイルを指定する (パスの先頭に%...%で定数を埋め込めます)
   ・インタフェース定義ファイルと同じディレクトリに インタフェース名_メソッド名.sql ファイルを作成する

実装クラスの作成

必要な実装クラスはありません。

diconファイルの作成

ADOdb を用いる場合の diconファイルを作成します。includeタグで adodb.diconをインクルードします。 findDeptByDeptnoメソッドに、dao(S2Container_SimpleDaoInterceptor) をアスペクトします。

XML形式 simpleDeptDao.dicon

<components>
    <include path="%S2CONTAINER_PHP5%/org/seasar/extension/db/adodb.dicon"/>
    <component name ="deptDao" class="DeptDao">
        <aspect pointcut="findDeptByDeptno">
            dao
        </aspect>
    </component>
</components>

INI形式 simpleDeptDao.ini

[components]
include{0} = "%S2CONTAINER_PHP5%/org/seasar/extension/db/adodb.dicon"

[deptDao]
class="DeptDao"
aspect{0}{pointcut} = "findDeptByDeptno"
aspect{0}{ref} = dao

実行スクリプトの作成

  • simpleDeptDao.diconを指定してコンテナを作成します。
  • コンテナより、deptDaoコンポーネントを取得します。
  • DEPTNO(10) で findDeptByDeptno メソッドを呼び出します。

simpleClient.php

<?php
require_once(dirname(__FILE__) . '/db.inc.php');
$PATH = EXAMPLE_DIR . "/extension/db/simpleDeptDao.dicon";
//$PATH = EXAMPLE_DIR . "/extension/db/simpleDeptDao.ini";

$container = S2ContainerFactory::create($PATH);
$dao = $container->getComponent('deptDao');
$result = $dao->findDeptByDeptno(10);
print_r($result);
?>

実行結果

% php simpleClient.php
Array
(
    [0] => Array
        (
            [0] => 10
            [1] => ACCOUNTING
            [2] => NEW YORK
            [3] => 0
        )
)
%

戻り値がオブジェクトの場合

データベース検索結果を指定したオブジェクトのプロパティ値として取得します。

インタフェースの定義

  • BeanDeptDaoインタフェースを定義します。
  • DEPTNO値で検索を行う findDeptByDeptnoメソッドを定義します。
  • 定数アノテーション(BEAN)で、DTO(Data Transfer Object)を設定します。
<?php
interface BeanDeptDao {
    const BEAN = "DeptDto";
    function findDeptByDeptno($deptno);
}
?>

各メソッドが発行するSQL文を指定する方法は3通りあります。
   ・定数アノテーション: メソッド名_QUERY に記述する
   ・定数アノテーション: メソッド名_FILE で外部ファイルを指定する (パスの先頭に%...%で定数を埋め込めます)
   ・インタフェース定義ファイルと同じディレクトリに インタフェース名_メソッド名.sql ファイルを作成する

3番目の方法を用い、findDeptByDeptnoが発行するSQL文を、BeanDeptDaoインタフェース定義ファイルと同じディレクトリに、 BeanDeptDao_findDeptByDeptno.sqlで作成します。

select * from dept where deptno = '{$deptno}'

実装クラスの作成

定数アノテーション(BEAN)で指定したDTOを作成します。

<?php
class DeptDto {
    private $deptno;
    private $dname;
    
    function DeptDto() {}
    
    function setDeptno($deptno){
    	$this->deptno = $deptno;
    }
    function getDeptno(){
        return $this->deptno;	
    }
    
    function setDname($dname){
    	$this->dname = $dname;
    }
    function getDname(){
        return $this->dname;
    }

    function __toString(){
    	$str = "deptno = " . $this->deptno . ", dname = " . $this->dname;
        return $str;	
    }
}
?>

データベース検索結果のうち、カラム名とDTOのプロパティ及びそのセッターメソッド名が対応する値のみ、定数アノテーション(BEAN)で指定した DTO のプロパティに設定されます。

 カラム名とプロパティ及びそのセッターメソッド名の対応
カラム名 プロパティ名 セッターメソッド名
deptno deptno setDeptno
dept_no deptNo setDeptNo
DEPTNO deptno setDeptno
DEPT_NO deptNo setDeptNo

diconファイルの作成

ADOdb を用いる場合の diconファイルを作成します。includeタグで adodb.diconをインクルードします。 findDeptByDeptnoメソッドに、dao(S2Container_SimpleDaoInterceptor) をアスペクトします。(Pear DBを使用する場合は、peardb.dicon をインクルードして下さい。)

XML形式 simpleDeptDao.dicon

<components>
    <include path="%S2CONTAINER_PHP5%/org/seasar/extension/db/adodb.dicon"/>
    <component name ="beanDeptDao" class="BeanDeptDao">
        <aspect pointcut="findDeptByDeptno">
            dao
        </aspect>
    </component>
</components>

INI形式 simpleDeptDao.ini

[components]
include{0} = "%S2CONTAINER_PHP5%/org/seasar/extension/db/adodb.dicon"

[beanDeptDao]
class="BeanDeptDao"
aspect{0}{pointcut} = "findDeptByDeptno"
aspect{0}{ref} = dao

実行スクリプトの作成

  • simpleDeptDao.diconを指定してコンテナを作成します。
  • コンテナより、beanDeptDaoコンポーネントを取得します。
  • DEPTNO(10) で findDeptByDeptno メソッドを呼び出します。

simpleBeanClient.php

<?php
require_once(dirname(__FILE__) . '/db.inc.php');
//$PATH = EXAMPLE_DIR . "/extension/db/simpleDeptDao.dicon";
$PATH = EXAMPLE_DIR . "/extension/db/simpleDeptDao.ini";

$container = S2ContainerFactory::create($PATH);
$dao = $container->getComponent('beanDeptDao');
$result = $dao->findDeptByDeptno(10);
print_r($result);
?>

実行結果

% php simpleBeanClient.php
Array
(
    [0] => DeptDto Object
        (
            [deptno:private] => 10
            [dname:private] => ACCOUNTING
        )

)
%

DeptDtoクラスのプロパティ deptno と dname に値が設定されています。データベース検索結果のLOCカラムやVERSIONNOカラムのデータは破棄されます。


S2Unit

S2では、コンテナを使った開発のテストを楽しくおこなえるようにテスティングフレームワークが組み込まれています。PHPUnit、PHPUnit2、SimpleTestを拡張しています。主な機能は以下のとおりです。

  • テストメソッド(testXxx)ごとに自動的にS2Containerを作成します。
  • S2Containerに対するregister()、getComponent()、include() が用意されています。
  • TestCaseに public なフィールドがあると、フィールド名と同じ名前のコンポーネントがコンテナに存在すれば自動的にセットされます。
  • テストメソッドが終わると自動セットされた値は自動的にクリア( null をセット)されます。
  • テストメソッド( testXxx )に対応する setUpXxx()、tearDownXxx() を定義しておくと、setUp()の後、tearDown()の前に自動的に呼び出されます。個別のテストメソッドごとの初期化・終了処理を簡単に行えるようになります。

Example

Pear PHPUnit2 を拡張した S2Container_S2PHPUnit2TestCase を用います。
このサンプルは、s2container.php5/src/examples/extension/unit/以下にあります。

テスト対象

s2container.php5/src/examples/extension/unit/src/foo/FooLogic.class.php

<?php
class FooLogic {

    function FooLogic() {
    }
    
    function showYear(){
    	return 2005;
    }
}
?>

diconファイル

s2container.php5/src/examples/extension/unit/src/foo/foo.ini

[logic]
class = FooLogic

テストクラス

s2container.php5/src/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.ini");   //--- dicon ファイルを include します
    }

    function testShowYear(){
        $year = $this->logic->showYear();
        $this->assertEquals($year , 2005);	
    }
}
?>

s2container.php5/src/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/src/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)
%

Pear PHPUnit と SimpleTest を用いた同様のサンプルが s2container.php5/src/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します。