Qual é a diferença entre type e virtualType

41

No di.xmlque vem com o Magento2, há um nó typee um nó virtualType. Minhas perguntas é o que é isso virtualTypee, em que caso deve ser usado em vez de type?

Em alguns lugares, parece um link simbólico ou reescreve:

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

Onde um caminho completo é alterado para outro, mas em outros lugares, parece ser usado como uma maneira de definir um apelido mais curto.

<virtualType name="lessFileSourceBase" type="Magento\Framework\View\File\Collector\Base">
David Manners
fonte
3
Eu não tenho idéia (ainda) o que isso quer dizer, mas você pode começar a cavar a partir daqui: Magento\Framework\ObjectManager\Config\Mapper\Dom::convert. Há uma switchdeclaração lá em algum lugar.
Marius
Obrigado @ Marius, também estou me perguntando se lessFileSourceBaseé limitado ao xml ou se isso também pode ser usado fora. Acho que é melhor eu cavar.
David Manners

Respostas:

84

Tipos virtuais são uma maneira de injetar diferentes dependências em classes existentes sem afetar outras classes.

Por exemplo, a Magento\Framework\Session\Storageclasse usa um $namespaceargumento em seu construtor, cujo padrão é o valor 'padrão', e você pode usar a typedefinição para alterar o espaço de nome para 'núcleo'.

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

A configuração acima faria com que todas as instâncias Magento\Framework\Session\Storagetivessem um namespace 'core'. O uso de um tipo virtual permite que o equivalente a uma subclasse seja criado, onde apenas a subclasse possui os valores alterados do argumento.

Na base de código, vemos as duas configurações a seguir:

<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>

O primeiro trecho cria um tipo virtual para o Magento\Core\Model\Session\Storagequal altera o espaço para nome e o segundo injeta o tipo virtual Magento\Framework\Session\Generic. Isso permite Magento\Framework\Session\Genericser personalizado sem afetar outras classes que também declaram uma dependência deMagento\Framework\Session\Storage

Chris O'Toole
fonte
Muito obrigado @ Chris finalmente alguma justificação lógica eu encontrei
Suman-PHP4U
Isso foi simples e a melhor demonstração.
Umar
Esta resposta é melhor que o doc oficial do Magento
Suman-PHP4U 17/03
<type>está usando uma classe virtual que realmente não existe. Dessa forma, a modificação do argumento virtualTypeentrará em vigor somente quando a classe que usa o virtualType for inicializada, como Magento\Framework\Session\Genericno exemplo
Arif Ahmad
21

Outra maneira de entender os tipos virtuais -

Digamos que você tenha uma classe \Class1, que tenha o seguinte construtor -

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

E \Class2tem o seguinte construtor -

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

Agora, você deseja alterar o tipo de $argOfClass2de \Class3para \Class4, mas somente quando \Class2é usado como $argOfClass1.

A maneira "antiga" de fazer isso seria adicionar o seguinte em di.xml-

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

onde \Class5é o seguinte:

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

Em vez de usar dessa maneira, você pode usar os tipos virtuais para realizar o mesmo, adicionando o seguinte a 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>

Como você pode ver, o uso do tipo virtual salvou o trabalho de criação de Class5.

Para referência adicional, sugiro ler o artigo de Alan Storm sobre tipos virtuais no Magento2 - http://alanstorm.com/magento_2_object_manager_virtual_types/

NoamN
fonte
1
boa expalinação,
Anand Ontigeri 12/03
Fácil de entender. Obrigado por compartilhar um exemplo tão básico.
Kalyan Chakravarthi V
10

No mesmo di.xmlarquivo, descobri que lessFileSourceBaseé passado como argumento para lessFileSourceBaseFilteredque é passado como argumento para lessFileSourceBaseSortedque é passado como argumento para tipo Magento\Framework\Less\File\Collector\Aggregated.

Não encontrei nenhuma outra ocorrência de lessFileSourceBase(ou lessFileSource) em outro arquivo, exceto di.xmlno módulo principal. Somente em alguns arquivos de cache, mas esses não são importantes.

Eu acho que se você não usar o tipo virtual em uma classe PHP, mas apenas nos diarquivos xml, não será necessário fazê-lo parecer um nome de classe e você poderá usar um alias.

Mas isso é pura especulação.
Será "divertido" tentar criar uma classe e injetar em seu construtor uma instância lessFileSourceBasepara ver como ela se comporta.

Marius
fonte
1
você perdeu as aspas em torno da palavra diversão;)
David Manners
1
@DavidManners. Direita. Eu consertei isso. :)
Marius
@ Marius: Se você alterar o \Magento\Framework\Session\Genericarquivo de origem em que depender, em Magento\Core\Model\Session\Storagevez de StorageInterfaceobter uma exceção 'Class Magento \ Core \ Model \ Session \ Storage não existe'. O motivo é que o ObjectManager não cria uma instância do virtualType, mas apenas o usa para determinar quais argumentos fornecer ao construtor do tipo concreto que é referenciado pela definição de virtualType ( Magento\Framework\Session\Storagepara o exemplo acima).
Chris O'Toole
É possível ver isso no Factory , onde $requestedTyperepresenta o tipo virtual e é usado para reunir argumentos, mas $typeé o tipo concreto para o qual o virtualType mapeia e é usado para a chamada de instanciação do objeto.
Chris O'Toole
Assim, mesmo se lessFileSourceBaseestava em um estilo mais namespace \ tipo de classe, não permitiria referência direta por outra classe php, apenas para injecção através da di.xml
Chris O'Toole