Как сделать сервис LoggerInterface общедоступным в Symfony 4

Я хочу, чтобы Psr\Log\LoggerInterface был общедоступным в symfony, чтобы иметь возможность получить его прямо из контейнера с помощью $container->get('Psr\Log\LoggerInterface').

Я пробовал следующее services.yaml:

_defaults:
 public: true

Psr\Log\LoggerInterface:
 public: true

Psr\Log\LoggerInterface:
 alias: 'logger'
 public: true

Psr\Log\LoggerInterface:
 alias: 'monolog.logger'
 public: true

Я не могу понять, почему так сложно переписать сервис.

$container->get('logger') получит регистратор, если у вас есть доступ ко всему контейнеру. Вы пытаетесь получить доступ к регистратору с контроллера или просто с какого-то сервиса?

Cerad 07.03.2019 13:57
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Symfony Station Communiqué - 17 февраля 2023 г
Symfony Station Communiqué - 17 февраля 2023 г
Это коммюнике первоначально появилось на Symfony Station , вашем источнике передовых новостей Symfony, PHP и кибербезопасности.
Управление ответами api для исключений на Symfony с помощью KernelEvents
Управление ответами api для исключений на Symfony с помощью KernelEvents
Много раз при создании api нам нужно возвращать клиентам разные ответы в зависимости от возникшего исключения.
1
1
1 561
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Использование $контейнер->получить() — плохая практика. Это нарушает многие хорошие принципы проектирования программного обеспечения.

Вместо этого вы должны использовать инъекцию конструктора.

class Foo
{
    protected $logger;

    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }
}
Ответ принят как подходящий

Как отмечалось ранее, прямой доступ к службам из контейнера не рекомендуется. Но мне было немного любопытно посмотреть, как сделать частную службу общедоступной. Я попробовал то, что было указано в вопросе, и подтвердил, что это не сработало.

Это может быть не самый простой подход, но проход компилятора поможет:

# src/Kernel.php
# Make the kernel a compiler pass
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
class Kernel extends BaseKernel implements CompilerPassInterface
...
public function process(ContainerBuilder $container)
{
    $logger = $container->getAlias(LoggerInterface::class);
    $logger->setPublic(true);
}

# And that should do the trick, you can confirm with
bin/console debug:container Psr\Log\LoggerInterface

Имейте в виду, что только сервисы, в которых внедрен полный контейнер, смогут воспользоваться этим. Контроллеры, унаследованные от AbstractController, имеют доступ только к небольшому количеству сервисов.

Взгляните на Подписчики услуг, если вам нужен регистратор в вашем контроллере или если вам просто нужен «лучший» способ сделать это.

Все говорят, что использование контейнера напрямую — плохая практика. Однако два момента. Никто не знает моих ситуаций. А во-вторых, никто не удосужился объявить параметры конструктора службы, которая на самом деле этой службе не нужна, но предназначена для ее дочерней службы.

FreeLightman 08.03.2019 05:32

Если очень хочется знать, зачем мне это нужно, я разработал пакет для удобных опций - github.com/mrself/php-параметры. У него нет документации. Но вскоре вы объявляете свойство следующим образом: ` /** * @Option() * @var CategoryRepository */ protected $categoryRepository; ` и у вас есть репозиторий после инициализации класса.

FreeLightman 08.03.2019 05:35

Для справки, я сказал «не рекомендуется», а не «плохо», потому что, конечно, бывают случаи, когда необходим доступ к контейнеру. Не уверен, что именно делает ваш пакет опций из вашего комментария. Просто для информации, есть аннотация /** @required */, которую можно использовать для автоматического внедрения зависимостей. Вы даже можете поместить его в трейт, и тогда любой класс, который использует трейт, получит зависимость без дополнительных усилий.

Cerad 08.03.2019 13:12
@required звучит интересно. Вы имеете в виду этот php-di.org/doc/annotations.html ?
FreeLightman 08.03.2019 14:27

Неправильный контейнер. Честно говоря, я не знаю, где именно это задокументировано. Несколько раз смотрел, но не нашел. Было обсуждение здесь. И здесь — это рабочий пример того, как он используется для внедрения маршрутизатора в RouterTrait. Затем вы можете использовать RouterTrait в любой другой службе, которой нужна возможность маршрутизации, не беспокоясь о внедрении маршрутизатора. Немного волшебно, но я нахожу это полезным.

Cerad 08.03.2019 14:48

Было бы избыточно иметь типаж для каждой службы. DI @Inject очень мощный. Мой пакет делает то же самое. Однако я разочарован тем, что не встретил DI раньше. Попробую заменить этот код на DI

FreeLightman 08.03.2019 14:51

Это прекрасно. Но опять же, имейте в виду, что контейнер Symfony не поддерживает все аннотации, которые поддерживает контейнер PHP_DI. Две совершенно разные кодовые базы. Я не думаю, что @Inject доступен из коробки. Не уверен, что вы подразумеваете под «избыточным». Я делаю трейты только для наиболее часто используемых сервисов. В противном случае я просто использую инъекцию конструктора. Но удачи.

Cerad 08.03.2019 15:03

Этот код все еще применяется для 3.4 и более поздних версий? Я добавил в свой appKernel.php (я переношу старое приложение 2.7) и проверил его запуск в отладчике, но, несмотря на установку общедоступного параметра, при следующем запросе службы он все еще находится в списке частных служб. РЕДАКТИРОВАТЬ - да, мне просто нужно было изменить имя службы на "логгер", т.е. $container->getAlias('logger'). О, так просто!

Steve Childs 10.12.2019 11:15

Большое спасибо, SteveChilds (и, конечно же, Cerad). Другая ситуация, когда это может потребоваться, — это когда у вас есть устаревший код, в котором вы не можете использовать D-I.

Asenar 17.12.2020 13:47

Другие вопросы по теме