📅  最后修改于: 2020-10-16 07:36:31             🧑  作者: Mango
Zend框架包含一个功能强大的服务定位器模式实现,称为zend-servicemanager 。 Zend框架广泛使用服务管理器来实现其所有功能。服务管理器为Zend框架提供了高级抽象。它还与Zend框架的所有其他组件很好地集成在一起。
可以使用作曲工具安装Service Manager组件。
composer require zendframework/zend-servicemanager
首先,所有服务都需要注册到服务管理器中。一旦将服务注册到服务器管理器系统中,就可以在任何时间以最小的努力对其进行访问。服务管理器提供许多选项来注册服务。一个简单的例子如下-
use Zend\ServiceManager\ServiceManager;
use Zend\ServiceManager\Factory\InvokableFactory;
use stdClass;
$serviceManager = new ServiceManager([
'factories' => [stdClass::class => InvokableFactory::class,],
]);
上面的代码使用Factory选项将stdClass注册到系统中。现在,我们可以使用服务管理器的get()方法随时获取stdClass的实例,如下所示。
use Zend\ServiceManager\ServiceManager;
$object = $serviceManager->get(stdClass::class);
get()方法共享检索到的对象,因此,多次调用get()方法返回的对象是一个实例。为了每次都获得不同的实例,服务管理器提供了另一种方法,即build()方法。
use Zend\ServiceManager\ServiceManager;
$a = $serviceManager->build(stdClass::class);
$b = $serviceManager->build(stdClass::class);
服务管理器提供了一组方法来注册组件。一些最重要的方法如下-
我们将在接下来的章节中详细讨论每一个。
工厂基本上是任何可调用的或实现FactoryInterface (Zend \ ServiceManager \ Factory \ FactoryInterface)的任何类。
FactoryInterface有一个方法-
public function __invoke(ContainerInterface $container, $requestedName, array
$options = null)
FactoryInterface的参数详细信息如下-
container(ContainerInterface) -它是ServiceManager的基本接口。它提供了获取其他服务的选项。
requestedName-这是服务名称。
options-它提供了服务所需的其他选项。
让我们创建一个实现FactoryInterface的简单类,并查看如何注册该类。
use stdClass;
class Test {
public function __construct(stdClass $sc) {
// use $sc
}
}
Test类取决于stdClass。
class TestFactory implements FactoryInterface {
public function __invoke(ContainerInterface $container, $requestedName,
array $options = null) {
$dep = $container->get(stdClass::class);
return new Test($dep);
}
}
TestFactory使用容器来检索stdClass,创建Test类的实例,然后将其返回。
现在让我们了解如何注册和使用Zend框架。
serviceManager $sc = new ServiceManager([
'factories' => [stdClass::class => InvokableFactory::class,
Test::class => TestFactory::class]
]);
$test = $sc->get(Test::class);
服务管理器提供了一个名为InvokableFactory的特殊工厂,以检索任何没有依赖关系的类。例如,stdClass的可使用由于stdClass的不依赖于任何其他类InvokableFactory进行配置。
serviceManager $sc = new ServiceManager([
'factories' => [stdClass::class => InvokableFactory::class]
]);
$stdC = $sc->get(stdClass::class);
但没有实施FactoryInterface或使用InvokableFactory使用内联方法如下面给出的另一种方式来检索对象。
$serviceManager = new ServiceManager([
'factories' => [
stdClass::class => InvokableFactory::class,
Test::class => function(ContainerInterface $container, $requestedName) {
$dep = $container->get(stdClass::class);
return new Test($dep);
},
],
]);
有时,我们可能需要创建对象,而这些对象只有在运行时才知道。可以使用从FactoryInterface派生的AbstractFactoryInterface来处理这种情况。
AbstractFactoryInterface定义了一种方法,用于检查是否可以在请求的实例处创建对象。如果可以创建对象,它将使用FactoryInterface的__invoke方法创建对象并返回它。
AbstractFactoryInterface的签名如下-
public function canCreate(ContainerInterface $container, $requestedName)
Initializer方法是一个特殊选项,可以为已经创建的服务注入附加的依赖关系。它实现了InitializerInterface ,唯一方法的签名如下:
public function(ContainerInterface $container, $instance)
function(ContainerInterface $container, $instance) {
if (! $instance instanceof EventManagerAwareInterface) {
return;
}
$instance->setEventManager($container->get(EventManager::class));
}
在上面的示例中,该方法检查实例是否为EventManagerAwareInterface类型。如果其类型为EventManagerAwareInterface ,则设置事件管理器对象,否则不设置。由于该方法可能会或可能不会设置依赖项,因此它不可靠,并会导致许多运行时问题。
Zend Framework通过DelegatorFactoryInterface支持委托人模式。它可以用来装饰服务。
该函数的签名如下-
public function __invoke(ContainerInterface $container,
$name, callable $callback, array $options = null
);
在这里, $ callback负责装饰服务实例。
惰性服务是在创建时不会完全初始化的那些服务之一。它们只是被引用,仅在真正需要时才进行初始化。最好的例子之一是数据库连接,它不一定在所有地方都需要。它是一种昂贵的资源,并且创建过程很耗时。 Zend Framework提供LazyServiceFactory从DelegatorFactoryInterface,能产生懒惰的服务与委托人概念的帮助和第三方代理经理,这就是所谓的ocramius代理经理的。
插件管理器扩展了服务管理器并提供了其他功能,例如实例验证。 Zend Framework广泛使用插件管理器。
例如,所有验证服务都在ValidationPluginManager下。
服务管理器提供了一些选项来扩展服务管理器的功能。它们是共享的,shared_by_default和别名。如前所述,默认情况下,检索到的对象在请求的对象之间共享,并且我们可以使用build()方法来获得一个不同的对象。我们还可以使用shared选项来指定要共享的服务。 shared_by_default与共享功能相同,不同之处在于它适用于所有服务。
$serviceManager = new ServiceManager([
'factories' => [
stdClass::class => InvokableFactory::class
],
'shared' => [
stdClass::class => false // will not be shared
],
'shared_by_default' => false, // will not be shared and applies to all service
]);
别名选项可用于为注册服务提供备用名称。这既有优点也有缺点。从积极的方面来说,我们可以为服务提供替代的简称。但是,与此同时,该名称可能会脱离上下文并引入错误。
aliases' => ['std' => stdClass::class, 'standard' => 'std']