我一直试图理解这个
http://symfony.com/doc/current/service_container/factories.html
但是似乎有一件事遗失了所有这一切 OR 我完全忽略了这一点。
该示例具有工厂类
class NewsletterManagerFactory
{
public static function createNewsletterManager()
{
$newsletterManager = new NewsletterManager();
// ...
return $newsletterManager;
}
}
然后通过服务将该工厂配置为NewsletterManager
服务的工厂类和方法。
services:
app.newsletter_manager_factory:
class: AppBundle\Email\NewsletterManagerFactory
app.newsletter_manager:
class: AppBundle\Email\NewsletterManager
factory: 'app.newsletter_manager_factory:createNewsletterManager'
现在我们有一个NewsletterManager
类通过NewsletterManagerFactory
factory:
参数了解services.yml
类
问题
如何使用此配置?现在NewsletterManager
内部暴露的内容允许我在工厂类中调用createNewsletterManager
?
据我所知,这两项服务仍完全分开?
答案 0 :(得分:5)
我曾经使用过这种模式。这是它的用例。
想象一下,您有多个窗口小部件类,即Acme\Widget1
,Acme\Widget2
,Acme\WidgetN
。
每个小部件都有高级实例化过程,因此您决定使用工厂。它还具有复杂的依赖关系链,每个窗口小部件都需要实例化。即Acme\Dependency1
,Acme\Dependency2
,Acme\Dependency3
。
所以你要做的就是创建一次带有依赖关系的Acme\WidgetFactory
服务。然后,您需要为每个窗口小部件指定Acme\WidgetFactory
作为工厂。如果窗口小部件实例化方式发生了某些变化,您只需要更改一个类和一个服务定义。所有1到N小部件服务保持不变。
以下是示例......
典型的实施方式:
acme.widget1:
class: Acme\Widget1
factory: ['Acme\Widget1', 'create']
arguments: ['@acme.dependency1', '@acme.dependency2', '@acme.dependencyN']
acme.widget2:
class: Acme\Widget2
factory: ['Acme\Widget2, 'create']
arguments: ['@acme.dependency1', '@acme.dependency2', '@acme.dependencyN']
acme.widgetN:
class: Acme\WidgetN
factory: ['Acme\WidgetN', 'create']
arguments: ['@acme.dependency1', '@acme.dependency2', '@acme.dependencyN']
在这里你有强烈的代码重复气味。如果你想改变一些东西你需要做N次。
相反,这是你可以做的。
acme.widget_factory:
class: Acme\WidgetFactory
arguments: ['@acme.dependency1', '@acme.dependency2', '@acme.dependencyN']
acme.widget1:
class: Acme\Widget1
factory: ['@acme.widget_factory', createWidget]
acme.widget2:
class: Acme\Widget2
factory: ['@acme.widget_factory', createWidget]
acme.widgetN:
class: Acme\WidgetN
factory: ['@acme.widget_factory', createWidget]
代码重复已经消失。
出现小不便......工厂不知道要实例化的具体类。我使用了以下技术。
我标记了每个小部件,然后在编译器传递期间向工厂添加了额外的参数。
acme.widget_factory:
class: Acme\WidgetFactory
arguments: ['@acme.dependency1', '@acme.dependency2', '@acme.dependencyN']
acme.widget1:
class: Acme\Widget1
factory: ['@acme.widget_factory', createWidget]
tags:
- { name: acme.widget }
acme.widget2:
class: Acme\Widget2
factory: ['@acme.widget_factory', createWidget]
tags:
- { name: acme.widget }
acme.widgetN:
class: Acme\WidgetN
factory: ['@acme.widget_factory', createWidget]
tags:
- { name: acme.widget }
然后在DepencencyInjection \ AcmeDemoExtension.php
class AcmeDemoExtension implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$widgets = $container->findTaggedServiceIds('acme.widget');
foreach ($widgets as $id => $tags) {
$definition = $container->getDefinition($id);
$definition->setArguments([$definition->getClass()]);
}
}
}
最后在工厂......
class AcmeWidgetFactory
{
//.....
public static function createWidget($class)
{
//.....
return new $class(/* dependencies */);
//.....
}
//.....
}
因此,当您执行$this->get('acme.widget1')
时,将调用以类名作为参数的工厂方法。 Factory已经拥有所有依赖项并且知道类实例化的逻辑。所以它完成所有工作并返回所需的小部件实例。
答案 1 :(得分:1)
这很简单。如果你要打电话
$nm = $container->get('app.newsletter_manager')
然后,工厂将自动创建新闻通讯管理器。