Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Аргументы, виртуальные типы и фабрики

Файл di.xml умеет больше, чем связывать интерфейс с классом. Через него в конструктор передают строки, числа и массивы, создают варианты класса без нового файла PHP, а сгенерированные фабрики и прокси управляют тем, когда объект создаётся.

Аргументы конструктора

Строку или число Magento не может подобрать по типу — значение задают в di.xml. Добавьте параметр в конструктор Greeter:

// app/code/Acme/Hello/Model/Greeter.php
public function __construct(
    private LoggerInterface $logger,
    private string $greeting = 'Здравствуйте',
) {}
<!-- app/code/Acme/Hello/etc/di.xml -->
<type name="Acme\Hello\Model\Greeter">
    <arguments>
        <argument name="greeting" xsi:type="string">Добрый день</argument>
    </arguments>
</type>

Имя аргумента совпадает с именем параметра конструктора без знака доллара. Если метод greet() использует $this->greeting, после bin/magento cache:clean страница /hello покажет «Добрый день, Анна!».

Значение xsi:typeЧто передаётся
string, number, booleanПростое значение
objectОбъект указанного класса
arrayМассив из элементов item

Массив

<!-- app/code/Acme/Hello/etc/di.xml -->
<type name="Acme\Hello\Model\Greeter">
    <arguments>
        <argument name="names" xsi:type="array">
            <item name="anna" xsi:type="string">Анна</item>
            <item name="ivan" xsi:type="string">Иван</item>
        </argument>
    </arguments>
</type>

Конструктор получит параметр array $names с двумя элементами. Другой модуль может добавить в этот массив свой item в собственном di.xml — так устроены многие точки расширения ядра.

Виртуальный тип

Виртуальный тип — существующий класс с другими аргументами, которому дали своё имя. Файл PHP для него не нужен. Частый пример — журнал, пишущий в отдельный файл:

<!-- app/code/Acme/Hello/etc/di.xml -->
<virtualType name="Acme\Hello\Logger\Handler" type="Magento\Framework\Logger\Handler\Base">
    <arguments>
        <argument name="fileName" xsi:type="string">/var/log/hello.log</argument>
    </arguments>
</virtualType>
 
<virtualType name="Acme\Hello\Logger" type="Magento\Framework\Logger\Monolog">
    <arguments>
        <argument name="name" xsi:type="string">hello</argument>
        <argument name="handlers" xsi:type="array">
            <item name="default" xsi:type="object">Acme\Hello\Logger\Handler</item>
        </argument>
    </arguments>
</virtualType>
 
<type name="Acme\Hello\Model\Greeter">
    <arguments>
        <argument name="logger" xsi:type="object">Acme\Hello\Logger</argument>
    </arguments>
</type>

Классов Acme\Hello\Logger и Acme\Hello\Logger\Handler на диске нет — это имена виртуальных типов. Теперь Greeter пишет в файл var/log/hello.log, а остальные классы — в общий журнал.

Фабрики

Объект из конструктора — один на весь запрос: все классы получают один и тот же экземпляр. Когда каждый раз нужен новый объект — товар, отзыв, запись, — просят фабрику. Её имя — имя класса плюс слово Factory:

// app/code/Acme/Hello/Model/DraftCreator.php
namespace Acme\Hello\Model;
 
use Magento\Catalog\Model\ProductFactory;
 
class DraftCreator
{
    public function __construct(private ProductFactory $productFactory) {}
 
    public function create(string $sku): \Magento\Catalog\Model\Product
    {
        $product = $this->productFactory->create();
        $product->setSku($sku);
 
        return $product;
    }
}

Каждый вызов create() возвращает новый пустой товар. Файл ProductFactory писать не нужно: Magento сгенерирует его в папке generated.

Прокси

Некоторые объекты дорого создавать, а нужны они не при каждом вызове. Прокси — сгенерированная обёртка, которая создаёт настоящий объект только при первом обращении к нему. Его подставляют в di.xml, дописав к имени класса \Proxy:

<!-- app/code/Acme/Hello/etc/di.xml -->
<type name="Acme\Hello\ViewModel\Greeting">
    <arguments>
        <argument name="greeter" xsi:type="object">Acme\Hello\Model\Greeter\Proxy</argument>
    </arguments>
</type>

Код класса Greeting при этом не меняется.

Частая ошибка

Слова Factory и Proxy вписывают не туда. Фабрику указывают типом параметра в конструкторе PHP, а прокси — только в di.xml. Тип Greeter\Proxy в конструкторе делает зависимость от сгенерированного класса явной и мешает её заменить.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.