我试图了解ZendFramework 2的一些原则,我想知道为什么要在ZF2 module.config.php 上注入服务,如果我可以使用加载实例的对象作曲家自动加载器。对于zend工厂来说,如果我可以轻松实现Factory类并在控制器中调用它,为什么要使用它?
答案 0 :(得分:2)
要事先清楚 - ServiceLocator
不是创建对象的must use
方式。您仍然可以直接创建对象,在很多情况下,这是一种非常有效的方法。
话虽如此,有几个原因可以解释为什么要将ServiceLocator
用于某些对象。不幸的是,Wikipedia Page对此并不太了解使用服务定位器的原因。我发现说明和示例here更有用。
对于余下的内容,我会使用class
和service
这两个词来互换。我将要求服务的类/对象命名为Consumer
,工厂负责创建服务factory
。
了解服务经理有一个非常重要的事实。服务名称不需要是类名。它可以是任何字符串(例如服务'名称)。
您要使用服务定位器的主要原因是:
constructions
(由工厂创建或直接实例化)重复使用服务
这可能是最容易看到的。通常,您有一个服务,并希望在您的应用程序中使用相同的实例。用例可以是从Configuration
服务到Caching Service
的任何内容。
我们肯定可以使用Singleton来确保全局只创建一个实例 - 这也可以。但这并没有提供其他论据的好处。
在Zf2中,默认情况下共享所有服务。因此,每次按名称请求服务时,您都将获得相同的实例。这可以在每个服务级别上启用(shared
配置中的service_manager
配置密钥。
抽象创作方式
理想情况下,消费者不应该知道如何创建所需的服务。这使它与所需服务更加分离。所有它需要知道的,就是说I require an instance of this service
。
使用服务管理器,您可以实现此目的:您要求服务经理获取特定服务,但您并不关心服务管理器实际创建此服务的方式。可能是服务管理器直接实例化它。它可能是一个工厂。消费者并不关心 - 它只关心结果,即服务的一个实例。
这样做的好处是,您可以透明地替换创建该服务的方式,而不必将消费者代码更新为创建该服务的新方式。
解耦模块
隐藏服务创建方式会导致解耦模块。我们假设您有两个模块Cache
和User
。 user
模块需要Cache
模块中的Cache
服务。您不必直接依赖Cache
模块和实现,而是通过名为cache
的服务隐藏该事实。 user
模块并不关心Cache
模块如何创建该服务。事实上,我们甚至可以用提供相同服务的另一个模块Cache
替换AdvancedCache
模块,而无需更新User
模块。 User
模块与特定模块无关 - 只存在名为cache
的服务。
抽象服务名称
在前面的例子中,我已经介绍了这个概念。每个服务都有一个全局名称 - 一个简单的字符串。在许多情况下,这是类名,但我们不限于此。
坚持上一个cache
服务示例:在这里,我们没有指定User
模块实际需要哪种类型的缓存 - 它并不关心。它可以是array
(内存中)缓存,file
缓存或memcache
缓存。
在其他地方,我们决定要全局使用哪个缓存,并将该具体实现分配给cache
的名称。所有需要cache
服务的模块现在都可以自动接收该实现而无需更新。
在Zf2中,这被广泛使用。以Request
服务为例。在许多情况下,这是Http\Request
的一个实例。但是在使用CLI时,这将是Console\Request
。但是,在请求Request
服务时,我们实际上并不关心哪一个服务,只要它们的行为相同。
另一个例子是Renderer
。根据我们想要为其呈现输出的环境,我们会收到不同的实现(HTML / Json / Console用法)。但我们的消费者并不需要知道我们为/.// p>呈现的具体实现
<强>委托者强>
Delegators可用于extend
工厂。我现在暂时将其排除在范围之外,因为这是一个更高级的用例。可以这么说,您可以在创建时扩展/代理服务创建。
答案 1 :(得分:0)
完成@Fge回答iI将向您展示一个示例,我自己试验了服务管理器如何有用,何时不是。
我在一些元素上创建了一个动态表单,我必须添加一些过滤器和一些验证器。
我向您展示了我的自定义服务方法,为我完成这项工作:
public function setValidators($form, $name, $validator, $nameFieldset)
{
$optionsSpace = [
'translator' => $this->translator,
'type' => NotEmpty::SPACE
];
$optionsString = [
'translator' => $this->translator,
'type' => NotEmpty::STRING
];
$optionsDigits = [
'translator' => $this->translator,
];
$form->getInputFilter()->get('items')
->get($nameFieldset)
->get($name)
->setRequired(true)
->getValidatorChain()
->attach($validator, true, 1)
->attach(new NotEmpty($optionsSpace), true, 2)
->attach(new NotEmpty($optionsString), true, 2)
->attach(new Digits($optionsDigits), true, 2);
return $form;
}
你可以看到我使用了一些数组,还有一些Zend \ Validators。
您还看到我在传递给那些验证器的每个选项数组上使用$this->translator
。为什么我通过翻译?我们来看一下验证器:
class NotEmpty extends AbstractValidator
抽象的验证器
abstract class AbstractValidator implements
Translator\TranslatorAwareInterface,
ValidatorInterface
如果您使用服务管理器,TranslatorAwareInterface
将由初始化程序实例化。如果你直接在你的服务中声明了新的验证器,那么情况并非如此,所以你必须在你的选项中设置它。