Symfony Tagged Service vs Factory

Tar*_*run 0 php symfony symfony-2.3

我是Symfony2的新手,有点困惑.对不起,这个问题听起来很傻.

这两个与工厂创建服务标签服务来假设创建一个工厂.

根据上面链接中的文档,我可以弄清楚的差异是:

对于标记服务:

您需要编写编译器传递,然后为每个服务定义一个标记.

然后编写一个工厂(任何类.这应该被称为工厂吗?),它将从编译器传递中获取所有标记服务的对象.还可以在此处创建一个getter方法,该方法将根据某些条件返回对象.

在使用工厂创建服务的情况下,您只能创建一个服务,并通过调用静态方法将其对象返回给您.

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

请让我理解两者的概念,让我感到开悟.

Igo*_*vić 9

工厂服务和标记服务具有完全不同的角色.我将尝试通过示例向您说明一些常见情况,当您可能想要使用其中一种情况时.

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

真实世界的用例

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

class PayPalPaymentService
{
    // ...

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

    // ...
}
Run Code Online (Sandbox Code Playgroud)

这对您很有用,但您意识到您需要有两个环境: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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

标记服务

这些完全是另一回事.在整个Symfony代码库中使用标记服务:用于FormTypes,Twig Extensions,Validator等.标记服务的概念是一种非常强大的扩展机制.它允许您将服务标记为用于特定目的的内容.正如我所说,在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();

    // ...
}
Run Code Online (Sandbox Code Playgroud)

现在,任何人都可以ProcessorAdapter在Github上实现并共享它作为一个包!他们所要做的只是ProcessorAdapter用你决定的一些标记来标记它们的实现,例如:'my_eshop_processor_adapter'.

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