Ліниві сервіси
Дата оновлення перекладу 2022-12-23
Ліниві сервіси
See also
Ще один спосіб впроваджувати ліниві сервіси - через підписника сервісу.
Чому ліниві сервіси?
У деяких випадках, ви можете захотіти впровадити сервіс, який трохи заважкий для інстанціювання,
але не завжди використовується всередині вашого обʼєкта. Наприклад, уявіть, що у вас є
NewsletterManager
і ви впроваджуєте у нього сервіс mailer
. Лише декілька методів у
вашому NewsletterManager
дійсно використовують mailer
, але навіть коли він вам не
потрібний, сервіс mailer
завжди інстанціюється, щоб побудувати ваш NewsletterManager
.
Рішенням цього є ліниві сервіси. З лінивим сервісом насправді впроваджується "проксі"
сервісу mailer
. Він виглядає та поводить себе точно так само, як і mailer
, крім
того, що mailer
насправді не інстанціюється до того як ви почнете якусь взаємодію
з проксі.
Caution
Ліниві сервіси не підтримують класи final, але ви можете використати Проксування інтерфейсу, щоб обійти це обмеження.
У версіях PHP до 8.0, ліниві сервіси не підтримують параметри зі значеннями
за замовчуванням для вбудованих PHP-класів (наприклад, PDO
).
6.2
Починаючи з Symfony 6.2, вам не потрібно встановлювати ніякий пакет (наприклад,
symfony/proxy-manager-bridge
), щоб використовувати інстанціювання лінивого сервісу.
Конфігурація
Ви можете відмітити сервіс як lazy
, змінивши його визначення:
- YAML
- XML
- PHP
1 2 3 4
# config/services.yaml
services:
App\Twig\AppExtension:
lazy: true
Як тільки ви впровадите сервіс в інший сервіс має бути впроваджено лінивий обʼєкт-привид
з таким же підписом класу, що представляє сервіс. Лінивий обʼєкт-привид - це обʼєкт,
який створюється порожнім і який може ініціалізувати сам себе, коли до нього отримують
доступ вперше. Теж саме відбувається, якщо викликати Container::get()
напряму.
Щоб перевірити, чи працює ваш лінивий сервіс, ви можете перевірити інтерфейс отриманого обʼєкта:
1 2
dump(class_implements($service));
// виведення повинно включати в себе "Symfony\Component\VarExporter\LazyGhostObjectInterface"
Проксування інтерфейсу
За лаштунками, проксі, згенеровані для лінивого завантаження сервісів, наслідують з класу, використовуваного сервісом. Однак, іноди це взагалі неможливо (наприклад, через те, що клас - final і не може бути розширений) або незручно.
Щоб обійти це обмеження, ви можете сконфігурувати проксі, щоб він реалізовував тільки конкретні інтерфейси.
- YAML
- XML
- PHP
1 2 3 4 5 6 7 8
# config/services.yaml
services:
App\Twig\AppExtension:
lazy: 'Twig\Extension\ExtensionInterface'
# or a complete definition:
lazy: true
tags:
- { name: 'proxy', interface: 'Twig\Extension\ExtensionInterface' }
Віртуальний проксі, впроваджений в інші сервіси, реалізовуватиме лише вказані інтерфейси і не розширюватиме оригінальний клас сервісу, що дозволить ліниве завантаження сервісів з використанням класів final. Ви можете сконфігурувати проксі так, щоб він реалізовував декілька інтерфейсів, додавши нові теги "proxy".
Tip
Ця функція може також діяти як охороень: враховуючи, що проксі не розширює оригінальний клас, лише методи, визначені інтерфейсом, можуть бути викликані; що запобігає виклику реалізації конкретних методів. Це також запобоігає впровадженню залежності взагалі, якщо ви додали підказку конкретної реалізації, замість інтерфейсу.