使用“工厂”来创建服务
全新的setFactory()方法从Symfony2.6起被引入。“工厂”相关语法也适用于2.6之前的老版本框架。
Symfony的服务容器提供了一个强有力的方式来控制对象建立,它允许你指定传给构造器的参数,以及调用setter方法并设置parameter参数。然而有些时候,以上方式仍然不能提供给你构造对象所需的每样东西。基于此种情形,你需要使用工厂方法来创建对象,并告诉服务容器去调用一个工厂方法,而不是直接实例化一个类。
假设你有一个工厂,用于配置并返回一个新的NewsletterManager
对象:
|
class NewsletterManagerFactory
{
public static function createNewsletterManager()
{
$newsletterManager = new NewsletterManager();
// ...
return $newsletterManager;
}
} |
为了让NewsletterManager
对象能够成为一个服务,你需要配置服务容器,以便能够使用工厂方法NewsletterManager::createNewsletterManager()
:
|
services:
newsletter_manager:
class: NewsletterManager
factory: [NewsletterManagerFactory, createNewsletterManager] |
|
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="Http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="newsletter_manager" class="NewsletterManager">
<factory class="NewsletterManagerFactory" method="createNewsletterManager" />
</service>
</services>
</container> |
|
use Symfony\Component\DependencyInjection\Definition;
// ...
$definition = new Definition('NewsletterManager');
$definition->setFactory(array('NewsletterManagerFactory', 'createNewsletterManager'));
$container->setDefinition('newsletter_manager', $definition); |
当使用工厂创建服务时,class
选项的值并不能影响到生产出来的服务。真实的类名只依赖于工场返回的对象。不过,这里配置的类名可能会被compiler pass所使用,因此还是赋与其一个有意义的名字比较好。
现在,上面的工厂方法将被静态调用。如果工厂类自身要求被实例化,进而调用对象里的相应方法,这时工厂自身应被设置为一个服务。同时,方法要改为“非静态”的(如get这种)。
|
services:
newsletter_manager.factory:
class: NewsletterManagerFactory
newsletter_manager:
class: NewsletterManager
factory: ["@newsletter_manager.factory", createNewsletterManager] |
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="newsletter_manager.factory" class="NewsletterManagerFactory" />
<service id="newsletter_manager" class="NewsletterManager">
<factory service="newsletter_manager.factory" method="createNewsletterManager" />
</service>
</services>
</container> |
1
2
3
4
5
6
7
8
9
10
11
12
|
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Definition;
// ...
$container->register('newsletter_manager.factory', 'NewsletterManagerFactory');
$newsletterManager = new Definition();
$newsletterManager->setFactory(array(
new Reference('newsletter_manager.factory'),
'createNewsletterManager'
));
$container->setDefinition('newsletter_manager', $newsletterManager); |
传递参数给“工厂方法” ¶
如果你需要传递参数给工厂方法,可以在服务容器中使用aruguments
选项。例如,假设前面的createNewsletterManager
方法需要一个templating
服务作为参数:
|
services:
newsletter_manager.factory:
class: NewsletterManagerFactory
newsletter_manager:
class: NewsletterManager
factory: ["@newsletter_manager.factory", createNewsletterManager]
arguments:
- '@templating' |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="newsletter_manager.factory" class="NewsletterManagerFactory"/>
<service id="newsletter_manager" class="NewsletterManager">
<factory service="newsletter_manager.factory" method="createNewsletterManager"/>
<argument type="service" id="templating"/>
</service>
</services>
</container> |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Definition;
// ...
$container->register('newsletter_manager.factory', 'NewsletterManagerFactory');
$newsletterManager = new Definition(
'NewsletterManager',
array(new Reference('templating'))
);
$newsletterManager->setFactory(array(
new Reference('newsletter_manager.factory'),
'createNewsletterManager'
));
$container->setDefinition('newsletter_manager', $newsletterManager); |