Symfony 4:使用服务工厂来实例化多个对象

Symfony 4: Using Factories of a Service to instantiate multiple objects

我有一个 class 路径,代表一条常规路径,可以用它做一些神奇的事情。每当我想在我的应用程序中处理路径时,我都想快速实例化一个 Path 对象并继续使用它。路径 class 有一些依赖关系,我想使用自动装配/依赖注入。

我试过的:

我将 class 作为一项服务部署到位并创建了一个工厂方法,类似于此处描述的内容:https://symfony.com/doc/current/service_container/factories.html。工厂方法接收依赖项作为参数并将它们存储在私有属性中。 只要在需要实例的地方使用依赖注入,我就能够获得新实例。这里的依赖没有问题。 现在的问题是我只能使用依赖注入获得一个实例。是的,我可以在上面克隆一个 "plain" 对象,但我想有更好的解决方案。 手动调用工厂方法是行不通的,因为那里有依赖注入。

服务和控制器:

<?
// Service
namespace App\Service;

class Path {
    private $dep;

    public function __construct(DependencyName $dep) {
        $this->dep = $dep;
    }

    public static function factory(DependencyName $dep) {
        $path = new Path($dep);
        return $path;
    }

    // some methods
}

// Controller
namespace App\Controller;

use App\Service\Path;

class SomeController {
    public function generatePaths() {
        for (int i = 0; i < 10; i++) {
            $paths[] = Path::factory(/* missing dependencies */);
        }
    }

    public function __construct(Path $path) {
        // here I can have one Path without a problem
        // but I need more than one
    }
}

在services.yaml中:

App\Service\Path:
        # call the static method
        factory: ['App\Service\Path', 'factory']

更一般:如何创建具有依赖项的服务的多个实例, 当我使用自动装配时? 解决方案不应仅限于控制器。我也需要在其他服务中使用此服务。

您可以在服务定义中使用 shared 选项:

In the service container, all services are shared by default. This means that [...] you'll get the same instance. In some cases, you might want to always get a new instance.

通过这样做(据我了解,您的 Dependency 始终相同)您将不再需要 factory 方法,并且可以将定义更改为:

App\Service\Path:
        class: App\Service\Path
        shared: false

要拥有多个实例,您不能使用注入,因此您需要实施 ServiceSubscriberInterface 并注册您的服务,这样您就可以在每次需要时从容器中手动检索它,同时仍然利用自动装配。

我不会详细介绍,因为有多个选项,其中一个可能比其他选项更有意义,但一旦实施,请执行以下操作:

$path = $this->get('path_builder'); // Whatever your alias is

每次都会给你一个新的实例。