В чем разница между типом и виртуальным типом

41

В di.xmlкомплекте с Magento2 есть узел typeи узел virtualType. Мои вопросы: что это такое virtualTypeи в каком случае его следует использовать вместо type?

В некоторых местах это выглядит как символическая ссылка или переписать:

<virtualType name="Magento\Core\Model\Session\Storage" type="Magento\Framework\Session\Storage">

Там, где один полный путь изменяется на другой, но в других местах он используется для определения более короткого псевдонима.

<virtualType name="lessFileSourceBase" type="Magento\Framework\View\File\Collector\Base">
Дэвид Мэннерс
источник
3
Я понятия не имею (пока) , что они даже означать , но вы можете начать копать отсюда: Magento\Framework\ObjectManager\Config\Mapper\Dom::convert. Там где-то есть switchутверждение.
Мариус
Спасибо @Marius, мне также интересно, lessFileSourceBaseограничен ли он xml или его можно использовать и снаружи. Думаю, мне лучше покопаться.
Дэвид Мэннерс

Ответы:

84

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

Например, Magento\Framework\Session\Storageкласс принимает $namespaceаргумент в своем конструкторе, который по умолчанию имеет значение «default», и вы можете использовать typeопределение, чтобы изменить пространство имен на «core».

<type name="Magento\Framework\Session\Storage">
    <arguments>
        <argument name="namespace" xsi:type="string">core</argument>
    </arguments>
</type>

Приведенный выше конфиг сделает так, чтобы все экземплярыMagento\Framework\Session\Storage имели пространство имен «core». Использование виртуального типа позволяет создать эквивалент подкласса, где только подкласс имеет измененные значения аргумента.

В кодовой базе мы видим следующие две конфигурации:

<virtualType name="Magento\Core\Model\Session\Storage" type="Magento\Framework\Session\Storage">
    <arguments>
        <argument name="namespace" xsi:type="string">core</argument>
    </arguments>
</virtualType>

<type name="Magento\Framework\Session\Generic">
    <arguments>
        <argument name="storage" xsi:type="object">Magento\Core\Model\Session\Storage</argument>
    </arguments>
</type>

Первый фрагмент создает виртуальный тип, для Magento\Core\Model\Session\Storageкоторого изменяется пространство имен, а второй вводит виртуальный тип в Magento\Framework\Session\Generic. Это позволяет Magento\Framework\Session\Genericнастраивать, не затрагивая другие классы, которые также объявляют зависимость отMagento\Framework\Session\Storage

Крис О'Тул
источник
Большое спасибо @Chris, наконец, я нашел какое-то логическое обоснование
Suman-PHP4U
Это была простая и лучшая демонстрация.
Умар
Этот ответ лучше официального документа Magento
Suman-PHP4U
<type>использует виртуальный класс, который на самом деле не существует. Таким образом, изменение аргумента в virtualTypeвступит в силу только тогда, когда будет инициализирован класс, использующий virtualType, как Magento\Framework\Session\Genericв примере
Ариф Ахмад
21

Еще один способ понять виртуальные типы -

Допустим, у вас есть класс \Class1, который имеет следующий конструктор -

public function __construct(\Class2 $argOfClass1){...}

И \Class2имеет следующий конструктор -

public function __construct(\Class3 $argOfClass2){...}

Теперь вы хотите изменить тип $argOfClass2с \Class3на на \Class4, но только когда \Class2используется как $argOfClass1.

«Старый» способ сделать это будет добавить следующее в di.xml-

<type name="Class1">
    <arguments>
         <argument name="argOfClass1" xsi:type="object">Class5</argument>
    </arguments>
</type>

где \Class5следующее:

class \Class5 extends \Class2{
    public function __construct(\Class4 $argOfClass2){...}
}

Вместо этого вы можете использовать виртуальные типы для достижения того же, добавив следующее в di.xml:

<virtualType name="Class5" type="Class2">
    <arguments>
        <argument name="argOfClass2" xsi:type="string">Class4</argument>
    </arguments>
</virtualType>

<type name="Class1">
    <arguments>
         <argument name="argOfClass1" xsi:type="object">Class5</argument>
    </arguments>
</type>

Как видите, использование виртуального типа избавило вас от работы по созданию Class5.

Для дальнейшего ознакомления предлагаю прочитать статью Алана Шторма о виртуальных типах в Magento2 - http://alanstorm.com/magento_2_object_manager_virtual_types/

NoamN
источник
1
хорошее объяснение,
Ананд Онтигери
Легко понять. Спасибо, что поделились таким базовым примером.
Калян Чакраварти V
10

В том же di.xmlфайле я обнаружил, что lessFileSourceBaseпередается в качестве аргумента для lessFileSourceBaseFilteredэтого передается в качестве аргумента для lessFileSourceBaseSortedэтого передается в качестве аргумента для типаMagento\Framework\Less\File\Collector\Aggregated .

Я не нашел другого вхождения lessFileSourceBase(или lessFileSource) в другом файле, кромеdi.xml из основного модуля. Только в некоторых файлах кэша, но они не важны.

Я думаю, если вы не собираетесь использовать виртуальный тип в классе PHP, а только в di файлах xml, вам не нужно, чтобы он выглядел как имя класса, и вы можете использовать псевдоним.

Но это всего лишь спекуляция.
Будет забавно попытаться создать класс и внедрить в его конструктор экземпляр класса, lessFileSourceBaseчтобы увидеть, как он себя ведет.

Мариус
источник
1
Вы пропустили кавычки вокруг слова веселья;)
Дэвид Мэннерс
1
@DavidManners. Правильно. Я починил это. :)
Мариус
@Marius: Если вы изменяете \Magento\Framework\Session\Genericисходный файл на зависимый, Magento\Core\Model\Session\Storageвместо него StorageInterfaceвы должны получить исключение «Class Magento \ Core \ Model \ Session \ Storage not Существует». Причина в том, что ObjectManager не создает экземпляр virtualType, а просто использует его, чтобы определить, какие аргументы нужно предоставить конструктору конкретного типа, на который ссылается определение virtualType ( Magento\Framework\Session\Storageдля приведенного выше примера).
Крис О'Тул
Это можно увидеть в Factory , где $requestedTypeпредставляет виртуальный тип и используется для сбора аргументов, но $typeэто конкретный тип, на который virtualType отображается и используется для вызова экземпляра объекта.
Крис О'Тул
Поэтому, даже если бы он lessFileSourceBaseбыл в более простом стиле имен / классов, он не позволял бы напрямую ссылаться на другой класс php, просто для внедрения через di.xml
Крис О'Тул