Symfony 标签服务与工厂

Symfony Tagged Service vs Factory

我是 Symfony2 的新手,有点困惑。对不起,如果这个问题听起来很愚蠢。

两者 creating service with factory and Tagged Services 都用于假设创建一个工厂。

根据上述链接中的文档,我可以找出不同之处:

For Tagged services:

you need to write a compiler pass and then define a tag for each service.

Then write a factory( any class. Should this be called a factory or not?), which will take objects of all the tagged services from compiler pass. Also create a getter method here which will return the object based upon some criteria.

如果使用工厂创建服务,您只能创建一个服务,它的对象将通过调用静态方法返回给您。

所以,我想,在标记服务中,您可以从多个服务中进行选择,而在按工厂创建服务的情况下,您只能创建一个服务。我认为tagged service已经在服务于一个工厂的目的了。当它们只能创建单个对象时,为什么我们需要工厂服务?可能是我在这里有一个误解,但是标记服务更好,因为编译器在缓存预热时通过 运行 并且标记服务本身存储在那里,所以它会更快。但是,服务也被缓存,所以应该没有太大区别。但我不确定这种概念化是否正确。

请让我明白两者的概念,让我开悟。

工厂服务和标签服务的作用完全不同。我将尝试通过示例向您说明一些您可能想要使用其中一种的常见情况。

工厂

当构建服务所需的某些参数在服务容器中不可用时,或者在实例化服务之前需要做一些准备时,通常会使用它。 Symfony 将自动检查您的服务是否有自己的工厂或直接从容器参数构建。

现实世界用例

您有处理 PayPal 付款的服务。要构建它,您需要在您的 PayPal 凭据和 API 端点 URL.

中传递它
class PayPalPaymentService
{
    // ...

    public function __construct(PayPalCredentials $credentials, $apiEndpoint)
    {
        // ...
    }

    // ...
}

这很适合您,但您意识到您需要两个环境:LiveSandbox。您的凭据和 API 端点 URL 都不同,具体取决于您所在的环境。

Symfony 有几种方法可以为您处理这个问题,但其中之一是通过 工厂服务:您创建一个工厂,它将实例化 PayPalPaymentService 根据您当前的本地环境。

class PayPalPaymentServiceFactory
{
    const SANDBOX_ENDPOINT = '...';
    const LIVE_ENDPOINT = '...';

    private $livePublic;
    // ...

    public function __construct($livePublic, $liveSecret, $sandboxPublic, $sandboxSecret, $kernelEnvironment)
    {
        $this->livePublic = $livePublic;
        // ...
    }

    public function create()
    {
        if ('prod' === $kernelEnvironment) {
            $credentials = new PayPalCredentials($this->livePublic, $this->liveSecret);
        } else {
            $credentials = new PayPalCredentials($this->sandboxPublic, $this->sandboxSecret);
        }
        $url = 'prod' === $kernelEnvironment ? self::LIVE_ENDPOINT : self::SANDBOX_ENDPOINT;

        return new PayPalPaymentService($credentials, $url);
    }
}

现在,每当您注入 PayPalPaymentService 时,容器都会首先要求您的 PayPalPaymentServiceFactory 创建它,然后注入它。

标记服务

这是完全不同的故事。标记服务在整个 Symfony 代码库中使用:用于 FormTypes、Twig 扩展、验证器等。标记服务的概念是一种非常强大的扩展机制。它允许您将您的服务标记为用于特定目的的服务。正如我所说,在 Symfony 代码库中已经有它们的示例,但这里是一个真正简化的示例,看看您可以用它们做什么:

您的网上商店有付款方式,并且您有支持的付款处理商列表。每个支付处理器都有自己的结帐页面。因此,您决定将其模块化并让其他人为其创建新的支付处理器。

在您的购物车页面上,您需要显示指向所有可用支付处理器结帐页面的链接,为此,您有一项服务可以为您提供所有可用的结帐链接:

class CheckoutLinksProvider
{
    /**
     * @var ProcessorAdapter[]
     */
    private $adapters;

    public function registerProcessor(ProcessorAdapter $adapter)
    {
        $this->adapters = $adapter;
    }

    public function getCheckoutLinks()
    {
        $links = [];
        foreach ($this->adapters as $adapter) {
            $links[] = $adapter->getCheckoutLink();
        }
        return $links;
    }
}

interface ProcessorAdapter
{
    /**
     * @return string Checkout URL link
     */
    public function getCheckoutLink();

    // ...
}

现在,任何人都可以实施 ProcessorAdapter 并在 Github 上将其作为捆绑包共享!他们所要做的就是用您决定的一些标签标记他们的 ProcessorAdapter 实现,例如:'my_eshop_processor_adapter'.

在您的核心电子商店系统编译器通道中,您现在可以选择所有 ProcessorAdapter 实现并将它们注册到您的 CheckoutLinksProvider 服务中。瞧!你有一个完全模块化的支付系统!任何人都可以创建对自定义处理器的支持,您只需下载它们的捆绑包并在您的内核中注册它们,结帐链接就会出现!