使用Symfony自动装配扩展类的正确方法

问题描述 投票:2回答:1

我想知道这是否是通过Symfonies自动装配扩展和使用类的正确方法。

例如,我有一个BaseClass实例化并自动连接实体管理器。

class BaseClass
{
  protected $entityManager;

  public function __construct(EntityManagerInterface $entityManager)
  {
    $this->entityManager = $entityManager;
  }

  protected function someMethodIWantToUse(Entity $something)
  {
    // Do something there
    $this->entityManager->persist($something);
    $this->entityManager->flush();
  }
}

然后,我有一个扩展BaseClass的子类,需要访问该方法。因此,我让它再次自动装配并传递给父构造函数。

class SubClass extends BaseClass
{
  private $handler;

  public function __construct(EntityManagerInterface $em, SomeHandler $handler)
  {
    parent::__construct($em);
    $this->handler = $handler;
  }

  public function SubClassMethod()
  {
    // Get some data or do something
    $entity = SomeEntityIGot();
    $this->someMethodIWantToUse($entity);
  }
}

现在,我想知道这是否是执行此操作的正确方法,或者我缺少某些东西,并且父类应该能够自行自动连接entitymanager?

php symfony
1个回答
0
投票

总结评论,是的,您的方法是正确的。根据您的用例,有其他选择。

这是您可以使用的方法:

1。扩展类并使用Constructor Injection(您的操作)

    class BaseClass {
        protected $some;

        public function __construct(SomeInterface $some)
        {
            $this->some = $some;
        }
    }

    class SubClass extends BaseClass {
        private $other;

        public function __construct(SomeInterface $some, OtherInterface $other)
        {
            parent::__construct($some);
            $this->other = $other;
        }
    }

2。 Setter Injection

    class BaseClass {
        protected $some;

        public function __construct(SomeInterface $some)
        {
            $this->some = $some;
        }
    }

    class SubClass extends BaseClass {
        private $other;

        public function setOther(OtherInterface $other)
        {
            $this->other = $other;
        }
    }

现在setOther将不会自动被调用,您必须通过在calls文件中指定services.yaml属性来“手动”调用它,如下所述:https://symfony.com/doc/current/service_container/calls.html。然后看起来像这样:

// services.yaml
App\SubClass:
    calls:
        - [setOther, ['@other']]

// services.yaml
app.sub_class:
    class: App\SubClass
    calls:
        - [setOther, ['@other']]

假定,OtherInterface的实现可在服务容器中作为@other使用。

[如果您使用的是自动装配,则是一个更优雅的解决方案,只需在此函数中添加@required批注,如下所述:https://symfony.com/doc/current/service_container/autowiring.html#autowiring-calls,如下所示:

/**
 * @required
 */
public function setOther(OtherInterface $other)
{
    $this->other = $other;
}

3。 Property Injection

    class BaseClass {
        protected $some;

        public function __construct(SomeInterface $some)
        {
            $this->some = $some;
        }
    }

    class SubClass extends BaseClass {
        public $other;
    }

与Setter Injection一样,您需要通过在services.yaml文件中指定该属性来告诉Symfony填充此属性:

// services.yaml
App\SubClass:
    properties:
        other: '@other'

// services.yaml
app.sub_class:
    class: App\SubClass
    properties:
        other: '@other'

假设,OtherInterface的实现可在服务容器中作为@other使用。


结论:由于有多种方法可以解决此问题,因此您需要确定用例的正确方法。我个人使用注释使用选项1(构造函数注入)或选项2(Setter注入)。它们都允许您使用typehints,从而使您的IDE可以帮助您编写简洁的代码。在90%的情况下,我会选择选项1,因为这样一来,对于每个阅读您的代码的人来说,一目了然__constructor函数可以提供哪些服务。Setter注入的一个用例是提供所有setXXX函数的基类,但是子类不需要全部。您可以在每个子类中都有一个构造函数,请求所需的服务,然后调用基类的setXXX方法。注意:这是一种极端情况,您可能不会遇到这种情况。

您可以直接在有关Service Container -> Types of Injection的Symfony文档中找到每种方法的优缺点列表>

© www.soinside.com 2019 - 2024. All rights reserved.