【问题标题】:ZF2 Deprecated: ServiceManagerAwareInterfaceZF2 已弃用:ServiceManagerAwareInterface
【发布时间】:2016-03-19 10:19:41
【问题描述】:

今天我更新了我的项目,我收到了这个警告:

已弃用:ServiceManagerAwareInterface 已弃用并将被 与 ServiceManagerAwareInitializer 一起在 3.0 版中删除。 请更新您的 X 类以删除实现,然后开始 而是通过工厂注入你的依赖项

我有一些实现ServiceManagerAwareInterface 的主要Base 类和扩展这些基类的多个类。

那么为这些类中的每一个创建额外的工厂类是一个好习惯吗?还是为每个模块使用 1 AbstractFactory 并在其中启动类更好?

使用 AbstractFactory 影响性能的剂量?

在许多类中注入单个(或两个)共享依赖项的最佳实践是什么?

更新: 即使我接受了@AlexP 的回答,但我对提供依赖项抛出构造函数有些担心。想象一下这个场景:我有一个控制器,有几个动作,免得说ActionA需要ServiceZ,ActionB需要ServiceY和ServiceX,而ServiceX也依赖于ServiceM和ServiceN。现在每次我调用 ActionA 时,我的控制器都会启动所有这些服务,但 ActionA 只需要 1 个服务,而我的控制器加载了 5 个服务......这是一个好习惯吗?这是正确的方法吗?这不会有很差的性能吗,因为在每次请求时都会启动我们在该请求期间根本不会使用的服务?

现在我允许每个服务/控制器处理自己的需求并在需要它们时加载服务。

这样我就不必启动多个我不会使用的服务,也不需要知道服务依赖项来使用它们。我知道这不被接受为最佳实践,但代码很干净,我更愿意牺牲“最佳实践”以获得更好的性能。

感谢任何人对此的意见。

【问题讨论】:

    标签: php dependency-injection zend-framework2 zend-framework3


    【解决方案1】:

    每个服务的工厂通常是一个理想的目标;但是,在很多情况下,当您拥有具有相似依赖关系的相似类时,为每个类创建该数量的工厂将是不必要且难以维护的。

    抽象工厂通过匹配它可以按名称创建的每个服务来解决多个工厂问题,然后使用一些自定义配置返回一个新实例。

    这引入了一些问题。

    • 调用$serviceManager->get()$serviceManager->has() 将要求抽象工厂检查它是否可以使用canCreateServiceWithName() 方法创建服务;对于多个抽象工厂,这可能会增加相当大的性能开销。

    • 抽象工厂没有服务“别名”的概念;服务管理器提供的功能。该实现要求您匹配服务的$requestedName。如果您使用完整的服务名称和别名来调用服务,则会出现此问题。

    • 抽象工厂与 ZF2 框架紧密耦合。

    框架的路线图非常专注于解决这些问题,ZF3 仍然提供抽象工厂,但它还提供introduces some improvements in factory design to encourage reusability,您已经可以利用它。

    请注意,工厂现在接受一个额外的必需参数$requestedName; v2 已经传递了这个参数,但它没有在接口本身中指定。 由于工厂现在可以接收服务名称,因此它们可能会被重新用于多个服务,主要是替换版本 3 中的抽象工厂

    所以我们已经可以多次使用标准工厂来实现类似的服务(在 ZF2 中)。

    一个非常简单的示例,说明如何使用一个工厂创建类似的服务。

    'service_manager' => [
        'factories' => [
            'My\Service\Foo' => 'My\Factory\SharedFactory',
            'My\Service\Bar' => 'My\Factory\SharedFactory',
            'My\Service\Baz' => 'My\Factory\SharedFactory',
        ],
    ],
    
    namespace My\Factory;
    
    class SharedFactory
    {
        public function __invoke($serviceLocator, $name, $requestedName)
        {
            if (! class_exists($requestedName)) {
                throw new ServiceNotCreatedException("$requestedName could not be found!");
            }
    
            return new $requestedName(
                $serviceLocator->get('SomeDependacy1'),
                $serviceLocator->get('SomeDependacy2')
            );
        }
    }
    

    您可以使用$requestedName 参数轻松扩展它以加载自定义服务配置,从而增加更大的灵活性。

    【讨论】:

    • 坦克的答案,不知道工厂提供服务名称,我更新了问题,看看你有没有时间。
    • 您的更新本身就是一个新问题。构造函数注入可以将海量的对象图加载到内存中,这很浪费。您可以通过更少的依赖项来减少开销,使您的类更具体,例如具有一种操作方法的控制器。然而,这意味着更多的工厂。另一个选项是Lazy services,它通过使用代理对象替换昂贵的对象实例化来帮助,这些代理对象在使用时返回真实对象。
    猜你喜欢
    • 1970-01-01
    • 2014-02-12
    • 2016-07-03
    • 1970-01-01
    • 2016-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多