PHP / Symfony: почему TwigExtension получает иную версию службы, отличную от контроллера? - PullRequest
0 голосов
/ 05 февраля 2019

Версии:

  • Версия Symfony: 4.2
  • Версия Twig: 2.6.2

Фон

  • IЯ обновляю существующее PHP-приложение с довольно старой версии Symfony (2.x) до 4.2.

Что происходит?

У меня есть shared сервис, который внедряется и используется в моем контроллере.

Существует также TwigExtension, которое получает тот же сервис и ожидает точно такой же экземпляр службы .

  • Почему TwigExtension полагается, что служба в любом случае является одним и тем же экземпляром?
    • Служба содержит конкретные данные, которые обрабатывает TwigExtension.Похоже, что в настоящее время служба используется как своего рода глобальный контейнер данных или сборщик данных для конкретного запроса.
  • В этот момент вы можете утверждать, что это звучит как сомнительная практика, и спрашивать, почему яна самом деле я делаю что-то вроде этого.
    • Я имею дело с существующим приложением, с существующим функционалом в зависимости от описанного поведения.
    • Я был бы рад получить приложениеработая на первом этапе, и меняйте подозрительные обходные пути на втором.

Ожидаемое поведение:

  • Ожидается общая службадля точного создания экземпляра один раз за запрос, и поэтому я также ожидаю, что TwigExtension получит тот же экземпляр, что и контроллер.

Фактическое поведение:

  • TwigExtension получает другоетолько что созданный экземпляр службы.

Поведение в старой версии (Symfony 2.x):

  • TwigExtension получил точно такой же сервисinstance.

То, что я пробовал:

  • Я попробовал это как с помощью инжектора конструктора, так и получения службы, вызвав $container->get('service') в TwigExtension
  • Я попробовал это сpublic: true / false
  • Я пробовал это в других местах, таких как прослушиватели событий, , где тот же экземпляр службы используется, как и ожидалось .

Мои вопросы:

  • Почему TwigExtension получает экземпляр службы, отличный от контроллера?
    • Почему существует другое поведение между TwigExtensions и, например, прослушивателями событий?
  • Какие общие исключения существуют для описанного выше ожидаемого поведения?
  • Можете ли вы указать мне любую полезную документацию?(конечно, я много гуглил и читал соответствующую документацию на сайте Symfony, но, может быть, я что-то упустил?)
  • Можете ли вы порекомендовать другой способ добиться чего-то похожего?

Ответы [ 2 ]

0 голосов
/ 06 февраля 2019

Получается, что для одного и того же класса были определены две службы.

Одна служба была определена вручную в services.yml с идентификатором службы 'service'.Определение сервисов вручную было единственным способом определения сервисов еще во времена Symfony 2.x.

Затем появился autowire и в основном определяет сервисы с идентификаторами их имен классов.Мы смогли убедиться, что это действительно проблема, используя «bin / console debug: container».Это является следствием обновления до Symfony 3.4+ и включения autowire.

Помимо создания сервисов, autowire также позволяет вводить сервис, печатая на клавиатуре имя класса.Если в контейнере найден соответствующий идентификатор сервиса, то сервис внедряется.Таким образом, в этом случае расширение ветки, вероятно, было изменено на использование ввода текста, в то время как контроллер использует $ container-> get, что привело к внедрению двух разных сервисов.Или, возможно, наоборот.

Одним из исправлений было бы использование псевдонима:

# services.yml
MyServiceClassName: service

Псевдоним в основном подавляет автоматическое создание второго сервиса.

A "Лучшим подходом (или наименее рекомендуемым) было бы прекратить использование $ container-> get и просто внедрить службу там, где это необходимо.Затем вы бы полностью отбросили определение 'service'.

В качестве последнего замечания: если бы самой службе потребовались какие-либо аргументы конструктора масштабирующего устройства (строки или целые числа), процесс autowire завершился бы ошибкой с сообщением об ошибке.Эти ошибки могут поначалу приводить в замешательство, поскольку у вас уже определен работающий сервис, но из-за того, что идентификатор сервиса отличается, autowire просто пашет вперед и пытается создать новый.

0 голосов
/ 05 февраля 2019

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

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

Если вы не нашли решения для этого, у вас есть две альтернативы для хранения ваших данных.Сессия для простых форматов и база данных для более сложного и долгосрочного хранения.

...