Подводя итог комментариям, да, ваш путь правильный. В зависимости от вашего варианта использования есть альтернативы.
Вот способы, которыми вы можете сделать это:
1. Расширение класса и использование Конструкторский впрыск (что вы делаете)
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. Сеттер Инъекция
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. Свойство Injection
class BaseClass {
protected $some;
public function __construct(SomeInterface $some)
{
$this->some = $some;
}
}
class SubClass extends BaseClass {
public $other;
}
Как и в случае Setter Injection, вы должны указать Symfony заполнить это свойство, указав его в файле services.yaml
следующим образом:
// services.yaml
App\SubClass:
properties:
other: '@other'
или
// services.yaml
app.sub_class:
class: App\SubClass
properties:
other: '@other'
при условии, что реализация OtherInterface
доступна как @other
в служебном контейнере.
Вывод:
Поскольку существуют разные способы решения этой проблемы, вам решать, как правильно выбрать вариант использования. Лично я использую аннотацию с опцией 1 (Инъекция конструктора) или опцией 2 (Инъекция сеттера). Они оба позволяют вам использовать шрифты и, таким образом, позволяют вашей IDE помогать писать чистый код.
В 90% случаев я бы выбрал вариант 1, поскольку для каждого, кто читает ваш код, понятно, какие услугидоступны одним взглядом на функцию __constructor
.
Один вариант использования для Setter Injection - это базовый класс, предлагающий все функции setXXX
, но тогда подклассам не нужны все из них. Вы можете иметь конструктор в каждом подклассе, запрашивая необходимые службы и затем вызывая методы setXXX
базового класса.
Примечание: это своего рода крайний случай, и вы, вероятно, не столкнетесь сthis.
Список преимуществ и недостатков каждого метода можно найти непосредственно в документации Symfony о Service Container -> Типы инъекций