Chapter 3. S2Container.PHP Reference

Table of Contents

3.1. S2Container Reference
3.1.1. Generation of S2Container
3.1.2. Getting a component
3.1.3. DI by automatic binding
3.1.4. DI by manual setup
3.1.5. Binding type setup
3.1.6. Instance type setup
3.1.7. ConstructClosure
3.2. S2ApplicationContext Reference
3.2.1. Import of Component
3.2.2. Generation of S2Container
3.2.3. Selection of a component
3.2.4. Manual Component Registration
3.2.5. Auto Aspect
3.2.6. Annotation
3.2.7. Management of Singleton S2Container instance
3.2.8. Initialization of S2ApplicationContext
3.3. S2ContainerFactory Reference
3.3.1. Creation of a DICON file
3.3.2. Generation of S2Container
3.4. DICON File Tag Reference
3.4.1. DOCTYPE (required)
3.4.2. components tag (required)
3.4.3. include tag
3.4.4. component tag
3.4.5. arg tag
3.4.6. property tag
3.4.7. initMethod tag
3.4.8. aspect tag
3.4.9. meta tag
3.4.10. description tag
3.5. S2Container configuration file

3.1. S2Container Reference

3.1.1. Generation of S2Container

S2Container is generated by the "create" method of S2ApplicationContext class or S2ContainerFactory class.

When using S2ApplicationContext class, S2ApplicationContext searches a class definition file with an import method from a file system, and then generates S2Container which has a search-results class as a component.

<?php
require_once('S2Container/S2Container.php');
seasar\container\S2ApplicationContext::import('/path/to/classes');
$container = seasar\container\S2ApplicationContext::create();

If using S2ContainerFactory class, S2ContainerFactory reads the DICON file which described the definition of the component, and generates S2Container.

<?php
require_once('S2Container/S2Container.php');
$container = seasar\container\factory\S2ContainerFactory::create('/path/to/dicon file');


3.1.2. Getting a component

The following method is used in order to take out a component from S2Container.

S2Container::getComponent($componentKey)

The class name or component name of a component is specified as an argument.($componentKey)
When there are two or more components which indicates the class specified in S2Container, since S2Container cannot specify which component should be returned, it will throw the exception "TooManyRegistrationRuntimeException". Therefore, please specify the class name it is decided uniquely that a component will be.
It is also the same as when taking out a component by a component name.

As an example, a component is defined by the DICON file as follows.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>
    <component name="action" class="example\IndexAction" />
</components>

As follows, you can get a component by specifying component name.

<?php
require_once('S2Container/S2Container.php');
$container = seasar\container\impl\S2ContainerFactory::create('/path/to/dicon file');
$component = $container->getComponent('action');

It is as follows, when specifying a class name and getting a component.

<?php
require_once('S2Container/S2Container.php');
$container = seasar\container\impl\S2ContainerFactory::create('/path/to/dicon file');
$component = $container->getComponent('example\IndexAction');

A component is also taken out by the class name which does not contain a namespace.

<?php
require_once('S2Container/S2Container.php');
$container = seasar\container\impl\S2ContainerFactory::create('/path/to/dicon file');
$component = $container->getComponent('IndexAction');

Also getting by the component name which the first letter of a class name made into the small letter. (IndexAction -> indexAction)

<?php
require_once('S2Container/S2Container.php');
$container = seasar\container\impl\S2ContainerFactory::create('/path/to/dicon file');
$component = $container->getComponent('indexAction');


3.1.3. DI by automatic binding

Automatic binding of S2Container solves the dependency between components by the information specified with the type hint of the property or setter method of a class and an interface. There are the following three types of Dependency Injection based on automatic binding.

  • Property Injection
  • Setter Method Injection
  • Constructor Injection

Property Injection. 

By property injection, Dependency Injection is performed to public property.
As a example, the case where a service class is injected to an action class is shown below. In an action class, a property for service component is implemented.

<?php
class Action {

    /**
     * @var Service
     */
    public $service = null;

    /**
     * action execution method
     */
    public function execute() {
        $result = $this->service->add(2,3);    
    }
}

When the default value of a public property is regarded as null, the component which uses a property name as a key is injected. With the above-mentioned sample, the component named "service" is going to be injected.
When you do not want to be injected to the property of which default value is null, please set seasar\container\Config::$DI_PROPERTY_NULL to false.

seasar\container\Config::$DI_PROPERTY_NULL = false;

By setting default property value by type hint, the component which be injected can be specified. A type hint is described like "S2Binding component name". Moreover, two or more components can be packed as array, and DI can be carried out. When doing DI as component packed array, please specify a type hint like "S2Binding component[]".

Let's create following action class at a current directory as "classes/Action.php".

<?php
class Action {

    /**
     * @var Service
     */
    public $service = 'S2Binding Service';

    /**
     * action execution method
     */
    public function execute() {
        $result = $this->service->add(2,3);
    }
}

The component name of the default value of a property is omissible. If a component name is omitted, a property name is treated as a component name. In the following example, a component name is "service".

    /**
     * @var Service
     */
    public $service = 'S2Binding';

The key of the type hint of a property can be set up by specifying string to seasar\container\Config::$PROPERTY_TYPEHINT_KEY. If seasar\container\Config::$PROPERTY_TYPEHINT_KEY is set as "DI", the default value of a property is set up as follows. The default value of seasar\container\Config::$PROPERTY_TYPEHINT_KEY is "S2Binding".

seasar\container\Config::$PROPERTY_TYPEHINT_KEY = 'DI';
    /**
     * @var Service
     */
    public $service = 'DI Service';

Let's create following service class at a current directory as "classes/Service.php".

<?php
class Service {

    /**
     * Sums are done.
     *
     * @param integer $a
     * @param integer $b
     * @return integer
     */
    public function add($a, $b) {
        return $a + $b;
    }
}

Please generate a container using S2ApplicationContext::create method and get the action component from the container. By the automatic binding function of S2Container, the service component will be injected to the action component.

<?php
require_once('S2Container/S2Container.php');

seasar\container\S2ApplicationContext::import(dirname(__FILE__) . '/classes');
$container = seasar\container\S2ApplicationContext::create();
$action    = $container->getComponent('Action');

$action->execute();

When generating a container using S2ContainerFactory class, please prepare the following DICON file.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>
    <component class="Action"/>
    <component class="Service"/>
</components>

A container is generated using S2ContainerFactory class and an action component is taken out. By the automatic binding function of S2Container, the service component will be injected to the action component.

<?php
require_once('S2Container/S2Container.php');

seasar\util\ClassLoader::import(dirname(__FILE__) . '/classes');
$container = seasar\container\S2ContainerFactory::create('/path/to/dicon file');
$action    = $container->getComponent('Action');

$action->execute();

[Note]NOTE

This Example is located at "example/AutoDI/property", "example/AutoDI/property_array"


Setter Method Injection. 

By setter method injection, Dependency Injection is performed to a property using setter method. There is naming convention in a setter method. In the case that a property name is "service", first character of a head is changed into a capital letter, "set" is added to a head, then "setService" is a setter method name of "service" property.

As a example, the case where Service class is injected to Action class is shown below.
In Action class, a setter method for service component is implemented. The type hint of the argument of a setter method is be Service class. Please create following Action class at a current directory as "classes/Action.php".

<?php
class Action {

    /**
     * @var Service
     */
    private $service = null;

    /**
     * setter method of service property
     *
     * @param Service $service
     */
    public function setService(Service $service) {
        $this->service = $service;
    }

    /**
     * action execution method
     */
    public function execute() {
        $result = $this->service->add(2,3);
    }
}

Let's create following service class at a current directory as "classes/Service.php".

<?php
class Service {

    /**
     * Sums are done.
     *
     * @param integer $a
     * @param integer $b
     * @return integer
     */
    public function add($a, $b) {
        return $a + $b;    
    }
}

As follows, a container is generated using S2ApplicationContext class and an action component is taken out from the container. By the automatic binding function of S2Container, the service component will be injected to the action component.

<?php
require_once('S2Container/S2Container.php');

seasar\container\S2ApplicationContext::import(dirname(__FILE__) . '/classes');
$container = seasar\container\S2ApplicationContext::create();
$action    = $container->getComponent('Action');

$action->execute();

When generating a container using S2ContainerFactory class, please prepare the following DICON file.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>
    <component class="Action"/>
    <component class="Service"/>
</components>

A container is generated using S2ContainerFactory class and an action component is taken out. By the automatic binding function of S2Container, the service component will be injected to the action component.

<?php
require_once('S2Container/S2Container.php');

seasar\util\ClassLoader::import(dirname(__FILE__) . '/classes');
$container = seasar\container\S2ContainerFactory::create('/path/to/dicon file');
$action    = $container->getComponent('Action');

$action->execute();

[Note]NOTE

This Example is located at "example/AutoDI/setter"


Constructor Injection. 

By constructor injection, Dependency Injection is performed to a property using constructor arguments.

As a example, the case where Service class is injected to Action class is shown below.
In Action class, a constructor argument for Service component is implemented. The type hint of the argument is be Service class. Let's create following Action class at a current directory as "classes/Action.php".

<?php
class Action {

    /**
     * @var Service
     */
    private $service = null;

    /**
     * construct action class
     *
     * @param Service $service
     */
    public function __construct(Service $service) {
        $this->service = $service;
    }

    /**
     * action execution method
     */
    public function execute() {
        $result = $this->service->add(2,3);
    }
}

Plese create following service class at a current directory as "classes/Service.php".

<?php
class Service {

    /**
     * Sums are done.
     *
     * @param integer $a
     * @param integer $b
     * @return integer
     */
    public function add($a, $b) {
        return $a + $b;    
    }
}

Please generate a container using S2ApplicationContext::create method and get the action component from the container. By the automatic binding function of S2Container, the service component will be injected to the action component.

<?php
require_once('S2Container/S2Container.php');

seasar\container\S2ApplicationContext::import(dirname(__FILE__) . '/classes');
$container = seasar\container\S2ApplicationContext::create();
$action    = $container->getComponent('Action');

$action->execute();

When generating a container using S2ContainerFactory class, please create following DICON file.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>
    <component class="Action"/>
    <component class="Service"/>
</components>

A container is generated using S2ContainerFactory class and an action component is taken out. By the automatic binding function of S2Container, the service component will be injected to the action component.

<?php
require_once('S2Container/S2Container.php');

seasar\util\ClassLoader::import(dirname(__FILE__) . '/classes');
$container = seasar\container\S2ContainerFactory::create('/path/to/diconファイル');
$action    = $container->getComponent('Action');

$action->execute();

[Note]NOTE

This Example is located at "example/AutoDI/consructor"


3.1.4. DI by manual setup

There are the following four types of Dependency Injection based on manual setup.

  • Property Injection
  • Setter Method Injection
  • Constructor Injection
  • InitMethod Injectioin

Property Injection. 

By property injection, Dependency Injection is performed to public property.

Setup by comment annotation. 

Let's create following action class at a current directory as "classes/Action.php". Comment annotation of each property describes the value, Expression or the reference to other component which are injected.

<?php
class Action {

    /**
     * @S2Binding('"seasar"')
     */
    public $name    = null;     // injected string "seasar"

    /**
     * @S2Binding('2000 + 8')
     */
    public $year    = null;     // injected integer "2008"

    /**
     * @S2Binding('Service')
     */
    public $service = null;     // injected Service component
}

Please create following service class at a current directory as "classes/Service.php".

<?php
class Service {

    /**
     * Sums are done.
     *
     * @param integer $a
     * @param integer $b
     * @return integer
     */
    public function add($a, $b) {
        return $a + $b;
    }
}

As follows, a container is generated using S2ApplicationContext class and an action component is taken out from the container. DI of the value and service component which were set up by annotation will be done.

<?php
require_once('S2Container/S2Container.php');

seasar\container\S2ApplicationContext::import(dirname(__FILE__) . '/classes');
$container = seasar\container\S2ApplicationContext::create();
$action    = $container->getComponent('Action');

var_dump($action);


Setup by DICON file. 

When setting up by a dicon file which is a definition file of S2Container, please create following DICON file.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>
    <component class="Action">
        <property name="name">"seasar"</property>
        <property name="year">2000 + 8</property>
        <property name="service">Service</property>
    </component>
    <component class="Service" />
</components>

The property of a component is specified using the property tag which is a child tag of a component tag. A property name is specified with a name attribute. The following item can be set to the body of a property tag.

  • The value surrounded by the (double) quote
  • Expression which described in PHP
  • Reference to other component

Let's create following action class at a current directory as "classes/Action.php".

<?php
class Action {
    public $name    = null;     // injected string "seasar"
    public $year    = null;     // injected integer "2008"
    public $service = null;     // injected Service component
}

Please create following service class at a current directory as "classes/Service.php".

<?php
class Service {

    /**
     * Sums are done.
     *
     * @param integer $a
     * @param integer $b
     * @return integer
     */
    public function add($a, $b) {
        return $a + $b;    
    }
}

As follows, a container is generated using S2ContainerFactory class and an action component is taken out from the container. DI of the value and service component which were set up by the DICON file will be done.

<?php
require_once('S2Container/S2Container.php');

seasar\util\ClassLoader::import(dirname(__FILE__) . '/classes');
$container = seasar\container\S2ContainerFactory::create('/path/to/dicon file');
$action    = $container->getComponent('Action');

var_dump($action);

[Note]NOTE

This Example is located at "example/ManualDI/property" and "example/ManualDI/property_array".


Setter Method Injection. 

By setter method injection, Dependency Injection is performed to a property using setter method.

Setup by comment annotation. 

Lets create following Action class at a current directory as "classes/Action.php". The setter method of each property is implemented. Comment annotation of each setter method describes the value, Expression or the reference to other component which are injected. When two or more components referred to exist, DI will be done by specifying array to the type hint of a setter method. When there is no type hint, "TooManyRegistrationRuntimeException" will be thrown.

<?php
class Action {
    private $name    = null;
    private $year    = null;
    private $service = null;

    /**
     * @S2Binding('"seasar"')
     */
    public function setName($name) {
        $this->name = $name;    // injected string "seasar"
    }
    
    /**
     * @S2Binding('2000 + 8')
     */
    public function setYear($year) {
        $this->year = $year;    // injected integer "2008"
    }
    
    /**
     * @S2Binding('Service')
     */
    public function setService(Service $service) {
        $this->service  = $service     // injected Service component
    }
}

Please create following Service class at a current directory as "classes/Service.php".

<?php
class Service {

    /**
     * Sums are done.
     *
     * @param integer $a
     * @param integer $b
     * @return integer
     */
    public function add($a, $b) {
        return $a + $b;    
    }
}

As follows, a container is generated using S2ApplicationContext class and an action component is taken out from the container. DI of the value and service component which were set up by annotation will be done.

<?php
require_once('S2Container/S2Container.php');

seasar\container\S2ApplicationContext::import(dirname(__FILE__) . '/classes');
$container = seasar\container\S2ApplicationContext::create();
$action    = $container->getComponent('Action');

var_dump($action);


Setup by DICON file. 

When setting up by a dicon file which is a definition file of S2Container, please create following DICON file.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>
    <component class="Action">
        <property name="name">"seasar"</property>
        <property name="year">2000 + 8</property>
        <property name="service">Service</property>
    </component>
    <component class="Service" />
</components>

The property of a component is specified using the property tag which is a child tag of a component tag. A property name is specified with a name attribute. The following item can be set to the body of a property tag.

  • The value surrounded by the (double) quote
  • Expression which described PHP
  • Reference to other components
When two or more components referred to exist, DI will be done by specifying array to the type hint of a setter method. When there is no type hint, "TooManyRegistrationRuntimeException" is going to be thrown.

Let's create following Action class at a current directory as "classes/Action.php". The setter method of each property is implemented.

<?php
class Action {
    private $name    = null;
    private $year    = null;
    private $service = null;

    public function setName($name) {
        $this->name = $name;    // injected string "seasar"
    }
    
    public function setYear($year) {
        $this->year = $year;    // injected integer "2008"
    }
    
    public function setService(Service $service) {
        $this->service  = $service;     // injected Service component
    }
}

Please create following Service class at a current directory as "classes/Service.php".

<?php
class Service {

    /**
     * Sums are done.
     *
     * @param integer $a
     * @param integer $b
     * @return integer
     */
    public function add($a, $b) {
        return $a + $b;    
    }
}

As follows, a container is generated using S2ContainerFactory class and an action component is taken out from the container. DI of the value and service component which were set up by the DICON file will be done.

<?php
require_once('S2Container/S2Container.php');

seasar\util\ClassLoader::import(dirname(__FILE__) . '/classes');
$container = seasar\container\S2ContainerFactory::create('/path/to/dicon file');
$action    = $container->getComponent('Action');

var_dump($action);

[Note]NOTE

This Example is located at "example/ManualDI/setter" and "example/ManualDI/setter_array".


Constructor Injection. 

By constructor injection, Dependency Injection is performed to a property using constructor arguments. Let's see the following DICON file.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>
    <component class="Action">
        <arg>"seasar"</arg>
        <arg>2000 + 8</arg>
        <arg>Service</arg>
    </component>
    <component class="Service" />
</components>

The argument of the constructor of a component is specified using the arg tag which is a child tag of a component tag. The following item can be set to the body of a arg tag.

  • The value surrounded by the (double) quote
  • Expression which described in PHP
  • Reference to other component
When two or more components referred to exist, DI will be done by specifying array to the type hint of a constructor argument. When there is no type hint, "TooManyRegistrationRuntimeException" is going to be thrown.

In the constructor of Action class, three arguments are received as follows.

<?php
class Action {
    private $name    = null;
    private $year    = null;
    private $service = null;

    public function __construct($name, $year, Service $service) {
        $this->name    = $name;    // injected string "seasar"
        $this->year    = $year;    // injected integer "2008"
        $this->service = $service;     // injected service component
    }
}

Please create following Service class at a current directory as "classes/Service.php".

<?php
class Service {

    /**
     * Sums are done.
     *
     * @param integer $a
     * @param integer $b
     * @return integer
     */
    public function add($a, $b) {
        return $a + $b;
    }
}

As follows, a container is generated using S2ContainerFactory class and an action component is taken out from the container. DI of the value and service component which were set up by the DICON file will be done.

<?php
require_once('S2Container/S2Container.php');

seasar\util\ClassLoader::import(dirname(__FILE__) . '/classes');
$container = seasar\container\S2ContainerFactory::create('/path/to/dicon file');
$action    = $container->getComponent('Action');

var_dump($action);

[Note]NOTE

This Example is located at "example/ManualDI/constructor" and "example/ManualDI/constructor_array".


InitMethod Injection. 

By InitMethod injection, Dependency Injection is performed using arbitrary public method.
Let's see the following DICON file.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>
    <component class="Action">
        <initMethod name="setName">
            <arg>"seasar"</arg>
        </initMethod>
        <initMethod name="setYear">
            <arg>2000 + 8</arg>
        </initMethod>
        <initMethod>
            $component->setService('new Service');
        </initMethod>
    </component>
</components>

InitMethod is specified by the initMthode tag which is a child tag of a component tag. The argument of a method is specified using an arg tag. The following item can be set to the body of a arg tag.

  • The value surrounded by the (double) quote
  • Expression which described in PHP
  • Reference to other component

Let's create following Action class at a current directory as "classes/Action.php". The InitMethods are implemented.

<?php
class Action {
    private $name    = null;
    private $year    = null;
    private $service = null;

    public function setName($name) {
        $this->name = $name;    // injected string "seasar"
    }
    
    public function setYear($year) {
        $this->year = $year;    // injected integer "2008"
    }
    
    public function setService(Service $service) {
        $this->service  = $service;     // injected Service component
    }
}

Please create following Service class at a current directory as "classes/Service.php".

<?php
class Service {

    /**
     * Sums are done.
     *
     * @param integer $a
     * @param integer $b
     * @return integer
     */
    public function add($a, $b) {
        return $a + $b;    
    }
}

As follows, a container is generated using S2ContainerFactory class and an action component is taken out from the container. DI of the value and service component which were set up by the DICON file will be done.

<?php
require_once('S2Container/S2Container.php');

seasar\util\ClassLoader::import(dirname(__FILE__) . '/classes');
$container = seasar\container\S2ContainerFactory::create('/path/to/dicon file');
$action    = $container->getComponent('Action');

var_dump($action);

[Note]NOTE

This Example is located at "example/ManualDI/method".


3.1.5. Binding type setup

In S2Container, a binding type can be specified per component. A binding type has the following two type.

Table 3.1. Binding Type

autoBindingExplanation
auto (default) It is followed when the argument of the constructor is specified by arg tag.
When the argument of the constructor is not specified, it binds automatically using type hint information.
It is followed when the property is specified by property tag.
When the property is not specified, it binds automatically using type hint information.
none It is followed when the argument of the constructor is specified by arg tag.
It is followed when the property is specified by property tag.

It is as follows when specifying a binding type by comment annotation.

<?php
/**
 * @S2Compnent('autoBinding' => 'none')
 */
class Service {}

It is as follows when specifying a binding type by DICON file.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>
    <component class="Service" autoBinding="none"/>
</components>

3.1.6. Instance type setup

In S2Container, instance management can be specified per component.

Table 3.2. Instance Type

instanceExplanation
singleton (default) Getting of a component by S2Container::getComponent() method will return the always same instance.
prototype A new instance is returned whenever it gets a component by S2Container::getComponent() method.

It is as follows when specifying an instance type by comment annotation.

<?php
/**
 * @S2Compnent('instance' => 'prototype')
 */
class Service {}

It is as follows when specifying a binding type by DICON file.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
"http://www.seasar.org/dtd/components21.dtd">
<components>
    <component class="Service" instance="prototype"/>
</components>

3.1.7. ConstructClosure

Processing that generates the component can be set with Closure. You can set ConstructClosure by the s2component function.

s2component('PDO')
  ->setConstructClosure(function(){
        return new PDO('sqlite:sqlite.db');
    });

The construct method is also defined as an alias for the setConstructClosure method.

s2component('PDO')->construct(function(){
    return new PDO('sqlite:sqlite.db');
});

The return value of ConstructClosure should be the class specified by the argument of the s2component function.
You can treat the instance generated by the static method etc. as a component.

$options = array('dbname' => 'sqlite.db');

s2component('Zend_Db_Adapter_Abstract')
  ->setName('zendPdo')
  ->setConstructClosure(function() use($options) {
        $db = Zend_Db::factory('PDO_SQLITE', $options);
        Zend_Db_Table_Abstract::setDefaultAdapter($db);
        return $db;
    });
[Note]NOTE

This Example is located at "example/ManualDI/closure".



© Copyright The Seasar Foundation and the others 2005-2010, all rights reserved.